mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-27 10:32:37 +00:00
Video avatar fixes
This commit is contained in:
parent
4755ee4261
commit
a34b7402be
@ -3,6 +3,8 @@ import Postbox
|
|||||||
import TelegramCore
|
import TelegramCore
|
||||||
import SyncCore
|
import SyncCore
|
||||||
|
|
||||||
|
private let minimalStreamableSize: Int = 384 * 1024
|
||||||
|
|
||||||
public func isMediaStreamable(message: Message, media: TelegramMediaFile) -> Bool {
|
public func isMediaStreamable(message: Message, media: TelegramMediaFile) -> Bool {
|
||||||
if message.containsSecretMedia {
|
if message.containsSecretMedia {
|
||||||
return false
|
return false
|
||||||
@ -13,7 +15,7 @@ public func isMediaStreamable(message: Message, media: TelegramMediaFile) -> Boo
|
|||||||
guard let size = media.size else {
|
guard let size = media.size else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if size < 256 * 1024 {
|
if size < minimalStreamableSize {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for attribute in media.attributes {
|
for attribute in media.attributes {
|
||||||
@ -36,7 +38,7 @@ public func isMediaStreamable(media: TelegramMediaFile) -> Bool {
|
|||||||
guard let size = media.size else {
|
guard let size = media.size else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if size < 1 * 1024 * 1024 {
|
if size < minimalStreamableSize {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for attribute in media.attributes {
|
for attribute in media.attributes {
|
||||||
@ -49,3 +51,11 @@ public func isMediaStreamable(media: TelegramMediaFile) -> Bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func isMediaStreamable(resource: MediaResource) -> Bool {
|
||||||
|
if let size = resource.size, size >= minimalStreamableSize {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -184,7 +184,7 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
|
|||||||
node?.itemChanged = { [weak self] index in
|
node?.itemChanged = { [weak self] index in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let pagerIndex = indexes[index]
|
let pagerIndex = indexes[index]
|
||||||
strongSelf.pager.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: pagerIndex))
|
strongSelf.pager.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: pagerIndex, synchronous: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ public struct GalleryItemIndexData: Equatable {
|
|||||||
public protocol GalleryItem {
|
public protocol GalleryItem {
|
||||||
var id: AnyHashable { get }
|
var id: AnyHashable { get }
|
||||||
|
|
||||||
func node() -> GalleryItemNode
|
func node(synchronous: Bool) -> GalleryItemNode
|
||||||
func updateNode(node: GalleryItemNode)
|
func updateNode(node: GalleryItemNode, synchronous: Bool)
|
||||||
func thumbnailItem() -> (Int64, GalleryThumbnailItem)?
|
func thumbnailItem() -> (Int64, GalleryThumbnailItem)?
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,12 +64,14 @@ public struct GalleryPagerTransaction {
|
|||||||
public let insertItems: [GalleryPagerInsertItem]
|
public let insertItems: [GalleryPagerInsertItem]
|
||||||
public let updateItems: [GalleryPagerUpdateItem]
|
public let updateItems: [GalleryPagerUpdateItem]
|
||||||
public let focusOnItem: Int?
|
public let focusOnItem: Int?
|
||||||
|
public let synchronous: Bool
|
||||||
|
|
||||||
public init(deleteItems: [Int], insertItems: [GalleryPagerInsertItem], updateItems: [GalleryPagerUpdateItem], focusOnItem: Int?) {
|
public init(deleteItems: [Int], insertItems: [GalleryPagerInsertItem], updateItems: [GalleryPagerUpdateItem], focusOnItem: Int?, synchronous: Bool) {
|
||||||
self.deleteItems = deleteItems
|
self.deleteItems = deleteItems
|
||||||
self.insertItems = insertItems
|
self.insertItems = insertItems
|
||||||
self.updateItems = updateItems
|
self.updateItems = updateItems
|
||||||
self.focusOnItem = focusOnItem
|
self.focusOnItem = focusOnItem
|
||||||
|
self.synchronous = synchronous
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,12 +312,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func replaceItems(_ items: [GalleryItem], centralItemIndex: Int?, keepFirst: Bool = false) {
|
public func replaceItems(_ items: [GalleryItem], centralItemIndex: Int?, synchronous: Bool = false) {
|
||||||
var items = items
|
|
||||||
if keepFirst && !self.items.isEmpty && !items.isEmpty {
|
|
||||||
items[0] = self.items[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateItems: [GalleryPagerUpdateItem] = []
|
var updateItems: [GalleryPagerUpdateItem] = []
|
||||||
var deleteItems: [Int] = []
|
var deleteItems: [Int] = []
|
||||||
var insertItems: [GalleryPagerInsertItem] = []
|
var insertItems: [GalleryPagerInsertItem] = []
|
||||||
@ -333,7 +330,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
insertItems.append(GalleryPagerInsertItem(index: i, item: items[i], previousIndex: previousIndexById[items[i].id]))
|
insertItems.append(GalleryPagerInsertItem(index: i, item: items[i], previousIndex: previousIndexById[items[i].id]))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.transaction(GalleryPagerTransaction(deleteItems: deleteItems, insertItems: insertItems, updateItems: updateItems, focusOnItem: centralItemIndex))
|
self.transaction(GalleryPagerTransaction(deleteItems: deleteItems, insertItems: insertItems, updateItems: updateItems, focusOnItem: centralItemIndex, synchronous: synchronous))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func transaction(_ transaction: GalleryPagerTransaction) {
|
public func transaction(_ transaction: GalleryPagerTransaction) {
|
||||||
@ -341,7 +338,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
self.items[updatedItem.previousIndex] = updatedItem.item
|
self.items[updatedItem.previousIndex] = updatedItem.item
|
||||||
if let itemNode = self.visibleItemNode(at: updatedItem.previousIndex) {
|
if let itemNode = self.visibleItemNode(at: updatedItem.previousIndex) {
|
||||||
//print("update visible node at \(updatedItem.previousIndex)")
|
//print("update visible node at \(updatedItem.previousIndex)")
|
||||||
updatedItem.item.updateNode(node: itemNode)
|
updatedItem.item.updateNode(node: itemNode, synchronous: transaction.synchronous)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +392,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
self.centralItemIndex = focusOnItem
|
self.centralItemIndex = focusOnItem
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateItemNodes(transition: .immediate, notify: transaction.focusOnItem != nil)
|
self.updateItemNodes(transition: .immediate, notify: transaction.focusOnItem != nil, synchronous: transaction.synchronous)
|
||||||
|
|
||||||
//print("visible indices after update \(self.itemNodes.map { $0.index })")
|
//print("visible indices after update \(self.itemNodes.map { $0.index })")
|
||||||
}
|
}
|
||||||
@ -425,18 +422,18 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
|
|
||||||
private func goToPreviousItem() {
|
private func goToPreviousItem() {
|
||||||
if let index = self.centralItemIndex, index > 0 {
|
if let index = self.centralItemIndex, index > 0 {
|
||||||
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func goToNextItem() {
|
private func goToNextItem() {
|
||||||
if let index = self.centralItemIndex, index < self.items.count - 1 {
|
if let index = self.centralItemIndex, index < self.items.count - 1 {
|
||||||
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1))
|
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1, synchronous: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeNodeForItem(at index: Int) -> GalleryItemNode {
|
private func makeNodeForItem(at index: Int, synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = self.items[index].node()
|
let node = self.items[index].node(synchronous: synchronous)
|
||||||
node.toggleControlsVisibility = self.toggleControlsVisibility
|
node.toggleControlsVisibility = self.toggleControlsVisibility
|
||||||
node.dismiss = self.dismiss
|
node.dismiss = self.dismiss
|
||||||
node.beginCustomDismiss = self.beginCustomDismiss
|
node.beginCustomDismiss = self.beginCustomDismiss
|
||||||
@ -475,7 +472,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
self.itemNodes.remove(at: internalIndex)
|
self.itemNodes.remove(at: internalIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateItemNodes(transition: ContainedViewLayoutTransition, forceOffsetReset: Bool = false, notify: Bool = false, forceLoad: Bool = false) {
|
private func updateItemNodes(transition: ContainedViewLayoutTransition, forceOffsetReset: Bool = false, notify: Bool = false, forceLoad: Bool = false, synchronous: Bool = false) {
|
||||||
if self.items.isEmpty || self.containerLayout == nil {
|
if self.items.isEmpty || self.containerLayout == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -487,7 +484,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
} while self.itemNodes.count > 0
|
} while self.itemNodes.count > 0
|
||||||
}
|
}
|
||||||
if self.itemNodes.isEmpty {
|
if self.itemNodes.isEmpty {
|
||||||
let node = self.makeNodeForItem(at: self.centralItemIndex ?? 0)
|
let node = self.makeNodeForItem(at: self.centralItemIndex ?? 0, synchronous: synchronous)
|
||||||
node.frame = CGRect(origin: CGPoint(), size: scrollView.bounds.size)
|
node.frame = CGRect(origin: CGPoint(), size: scrollView.bounds.size)
|
||||||
if let containerLayout = self.containerLayout {
|
if let containerLayout = self.containerLayout {
|
||||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||||
@ -502,7 +499,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
if let centralItemIndex = self.centralItemIndex, let centralItemNode = self.visibleItemNode(at: centralItemIndex) {
|
if let centralItemIndex = self.centralItemIndex, let centralItemNode = self.visibleItemNode(at: centralItemIndex) {
|
||||||
if centralItemIndex != 0 {
|
if centralItemIndex != 0 {
|
||||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex - 1) == nil {
|
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex - 1) == nil {
|
||||||
let node = self.makeNodeForItem(at: centralItemIndex - 1)
|
let node = self.makeNodeForItem(at: centralItemIndex - 1, synchronous: synchronous)
|
||||||
node.frame = centralItemNode.frame.offsetBy(dx: -centralItemNode.frame.size.width - self.pageGap, dy: 0.0)
|
node.frame = centralItemNode.frame.offsetBy(dx: -centralItemNode.frame.size.width - self.pageGap, dy: 0.0)
|
||||||
if let containerLayout = self.containerLayout {
|
if let containerLayout = self.containerLayout {
|
||||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||||
@ -513,7 +510,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
|
|
||||||
if centralItemIndex != self.items.count - 1 {
|
if centralItemIndex != self.items.count - 1 {
|
||||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex + 1) == nil {
|
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex + 1) == nil {
|
||||||
let node = self.makeNodeForItem(at: centralItemIndex + 1)
|
let node = self.makeNodeForItem(at: centralItemIndex + 1, synchronous: synchronous)
|
||||||
node.frame = centralItemNode.frame.offsetBy(dx: centralItemNode.frame.size.width + self.pageGap, dy: 0.0)
|
node.frame = centralItemNode.frame.offsetBy(dx: centralItemNode.frame.size.width + self.pageGap, dy: 0.0)
|
||||||
if let containerLayout = self.containerLayout {
|
if let containerLayout = self.containerLayout {
|
||||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||||
@ -549,7 +546,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
|
|
||||||
if centralItemCandidateNode.index != 0 {
|
if centralItemCandidateNode.index != 0 {
|
||||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemCandidateNode.index - 1) == nil {
|
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemCandidateNode.index - 1) == nil {
|
||||||
let node = self.makeNodeForItem(at: centralItemCandidateNode.index - 1)
|
let node = self.makeNodeForItem(at: centralItemCandidateNode.index - 1, synchronous: synchronous)
|
||||||
node.frame = centralItemCandidateNode.frame.offsetBy(dx: -centralItemCandidateNode.frame.size.width - self.pageGap, dy: 0.0)
|
node.frame = centralItemCandidateNode.frame.offsetBy(dx: -centralItemCandidateNode.frame.size.width - self.pageGap, dy: 0.0)
|
||||||
if let containerLayout = self.containerLayout {
|
if let containerLayout = self.containerLayout {
|
||||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||||
@ -560,7 +557,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
|
|||||||
|
|
||||||
if centralItemCandidateNode.index != items.count - 1 {
|
if centralItemCandidateNode.index != items.count - 1 {
|
||||||
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemCandidateNode.index + 1) == nil {
|
if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemCandidateNode.index + 1) == nil {
|
||||||
let node = self.makeNodeForItem(at: centralItemCandidateNode.index + 1)
|
let node = self.makeNodeForItem(at: centralItemCandidateNode.index + 1, synchronous: synchronous)
|
||||||
node.frame = centralItemCandidateNode.frame.offsetBy(dx: centralItemCandidateNode.frame.size.width + self.pageGap, dy: 0.0)
|
node.frame = centralItemCandidateNode.frame.offsetBy(dx: centralItemCandidateNode.frame.size.width + self.pageGap, dy: 0.0)
|
||||||
if let containerLayout = self.containerLayout {
|
if let containerLayout = self.containerLayout {
|
||||||
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class ChatAnimationGalleryItem: GalleryItem {
|
|||||||
self.location = location
|
self.location = location
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = ChatAnimationGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
let node = ChatAnimationGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
||||||
|
|
||||||
for media in self.message.media {
|
for media in self.message.media {
|
||||||
@ -46,7 +46,7 @@ class ChatAnimationGalleryItem: GalleryItem {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? ChatAnimationGalleryItemNode {
|
if let node = node as? ChatAnimationGalleryItemNode {
|
||||||
node.setMessage(self.message)
|
node.setMessage(self.message)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class ChatDocumentGalleryItem: GalleryItem {
|
|||||||
self.location = location
|
self.location = location
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = ChatDocumentGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
let node = ChatDocumentGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
||||||
|
|
||||||
for media in self.message.media {
|
for media in self.message.media {
|
||||||
@ -51,7 +51,7 @@ class ChatDocumentGalleryItem: GalleryItem {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? ChatDocumentGalleryItemNode, let location = self.location {
|
if let node = node as? ChatDocumentGalleryItemNode, let location = self.location {
|
||||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
||||||
node.setMessage(self.message)
|
node.setMessage(self.message)
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class ChatExternalFileGalleryItem: GalleryItem {
|
|||||||
self.location = location
|
self.location = location
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = ChatExternalFileGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
let node = ChatExternalFileGalleryItemNode(context: self.context, presentationData: self.presentationData)
|
||||||
|
|
||||||
for media in self.message.media {
|
for media in self.message.media {
|
||||||
@ -52,7 +52,7 @@ class ChatExternalFileGalleryItem: GalleryItem {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? ChatExternalFileGalleryItemNode, let location = self.location {
|
if let node = node as? ChatExternalFileGalleryItemNode, let location = self.location {
|
||||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
||||||
node.setMessage(self.message)
|
node.setMessage(self.message)
|
||||||
|
|||||||
@ -101,7 +101,7 @@ class ChatImageGalleryItem: GalleryItem {
|
|||||||
self.present = present
|
self.present = present
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = ChatImageGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present)
|
let node = ChatImageGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present)
|
||||||
|
|
||||||
for media in self.message.media {
|
for media in self.message.media {
|
||||||
@ -131,7 +131,7 @@ class ChatImageGalleryItem: GalleryItem {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? ChatImageGalleryItemNode, let location = self.location {
|
if let node = node as? ChatImageGalleryItemNode, let location = self.location {
|
||||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").0))
|
||||||
|
|
||||||
|
|||||||
@ -66,7 +66,7 @@ public class UniversalVideoGalleryItem: GalleryItem {
|
|||||||
self.present = present
|
self.present = present
|
||||||
}
|
}
|
||||||
|
|
||||||
public func node() -> GalleryItemNode {
|
public func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = UniversalVideoGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present)
|
let node = UniversalVideoGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present)
|
||||||
|
|
||||||
if let indexData = self.indexData {
|
if let indexData = self.indexData {
|
||||||
@ -78,7 +78,7 @@ public class UniversalVideoGalleryItem: GalleryItem {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateNode(node: GalleryItemNode) {
|
public func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? UniversalVideoGalleryItemNode {
|
if let node = node as? UniversalVideoGalleryItemNode {
|
||||||
if let indexData = self.indexData {
|
if let indexData = self.indexData {
|
||||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class InstantImageGalleryItem: GalleryItem {
|
|||||||
self.openUrlOptions = openUrlOptions
|
self.openUrlOptions = openUrlOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = InstantImageGalleryItemNode(context: self.context, presentationData: self.presentationData, openUrl: self.openUrl, openUrlOptions: self.openUrlOptions)
|
let node = InstantImageGalleryItemNode(context: self.context, presentationData: self.presentationData, openUrl: self.openUrl, openUrlOptions: self.openUrlOptions)
|
||||||
|
|
||||||
node.setImage(imageReference: self.imageReference)
|
node.setImage(imageReference: self.imageReference)
|
||||||
@ -76,7 +76,7 @@ class InstantImageGalleryItem: GalleryItem {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? InstantImageGalleryItemNode {
|
if let node = node as? InstantImageGalleryItemNode {
|
||||||
if let location = self.location {
|
if let location = self.location {
|
||||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.position + 1)", "\(location.totalCount)").0))
|
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.position + 1)", "\(location.totalCount)").0))
|
||||||
|
|||||||
@ -221,7 +221,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
|
|||||||
if strongSelf.isViewLoaded {
|
if strongSelf.isViewLoaded {
|
||||||
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
|
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
|
||||||
$0.item(context: context, webPage: webPage, message: message, presentationData: strongSelf.presentationData, fromPlayingVideo: fromPlayingVideo, landscape: landscape, openUrl: strongSelf.innerOpenUrl, openUrlOptions: strongSelf.openUrlOptions)
|
$0.item(context: context, webPage: webPage, message: message, presentationData: strongSelf.presentationData, fromPlayingVideo: fromPlayingVideo, landscape: landscape, openUrl: strongSelf.innerOpenUrl, openUrlOptions: strongSelf.openUrlOptions)
|
||||||
}), centralItemIndex: centralIndex, keepFirst: false)
|
}), centralItemIndex: centralIndex)
|
||||||
|
|
||||||
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
||||||
strongSelf?.didSetReady = true
|
strongSelf?.didSetReady = true
|
||||||
|
|||||||
@ -81,7 +81,6 @@
|
|||||||
#import <LegacyComponents/TGCameraMainTabletView.h>
|
#import <LegacyComponents/TGCameraMainTabletView.h>
|
||||||
#import <LegacyComponents/TGCameraMainView.h>
|
#import <LegacyComponents/TGCameraMainView.h>
|
||||||
#import <LegacyComponents/TGCameraModeControl.h>
|
#import <LegacyComponents/TGCameraModeControl.h>
|
||||||
#import <LegacyComponents/TGCameraPhotoPreviewController.h>
|
|
||||||
#import <LegacyComponents/TGCameraPreviewView.h>
|
#import <LegacyComponents/TGCameraPreviewView.h>
|
||||||
#import <LegacyComponents/TGCameraSegmentsView.h>
|
#import <LegacyComponents/TGCameraSegmentsView.h>
|
||||||
#import <LegacyComponents/TGCameraShutterButton.h>
|
#import <LegacyComponents/TGCameraShutterButton.h>
|
||||||
|
|||||||
@ -25,7 +25,8 @@ typedef enum
|
|||||||
PGCameraModePhoto,
|
PGCameraModePhoto,
|
||||||
PGCameraModeVideo,
|
PGCameraModeVideo,
|
||||||
PGCameraModeSquarePhoto,
|
PGCameraModeSquarePhoto,
|
||||||
PGCameraModeSquareVideo
|
PGCameraModeSquareVideo,
|
||||||
|
PGCameraModeSquareSwing
|
||||||
} PGCameraMode;
|
} PGCameraMode;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
#import <LegacyComponents/TGOverlayController.h>
|
|
||||||
#import <LegacyComponents/LegacyComponentsContext.h>
|
|
||||||
|
|
||||||
@class PGCameraShotMetadata;
|
|
||||||
@class PGPhotoEditorValues;
|
|
||||||
@class TGSuggestionContext;
|
|
||||||
|
|
||||||
@interface TGCameraPhotoPreviewController : TGOverlayController
|
|
||||||
|
|
||||||
@property (nonatomic, assign) bool allowCaptions;
|
|
||||||
|
|
||||||
@property (nonatomic, copy) CGRect(^beginTransitionIn)(void);
|
|
||||||
@property (nonatomic, copy) CGRect(^beginTransitionOut)(CGRect referenceFrame);
|
|
||||||
|
|
||||||
@property (nonatomic, copy) void(^finishedTransitionIn)(void);
|
|
||||||
|
|
||||||
@property (nonatomic, copy) void (^photoEditorShown)(void);
|
|
||||||
@property (nonatomic, copy) void (^photoEditorHidden)(void);
|
|
||||||
|
|
||||||
@property (nonatomic, copy) void(^retakePressed)(void);
|
|
||||||
@property (nonatomic, copy) void(^sendPressed)(TGOverlayController *controller, UIImage *resultImage, NSString *caption, NSArray *entities, NSArray *stickers, NSNumber *timer);
|
|
||||||
|
|
||||||
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
|
|
||||||
@property (nonatomic, assign) bool shouldStoreAssets;
|
|
||||||
@property (nonatomic, assign) bool hasTimer;
|
|
||||||
@property (nonatomic, assign) bool hasSilentPosting;
|
|
||||||
@property (nonatomic, assign) bool hasSchedule;
|
|
||||||
|
|
||||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context image:(UIImage *)image metadata:(PGCameraShotMetadata *)metadata recipientName:(NSString *)recipientName saveCapturedMedia:(bool)saveCapturedMedia saveEditedPhotos:(bool)saveEditedPhotos;
|
|
||||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context image:(UIImage *)image metadata:(PGCameraShotMetadata *)metadata recipientName:(NSString *)recipientName backButtonTitle:(NSString *)backButtonTitle doneButtonTitle:(NSString *)doneButtonTitle saveCapturedMedia:(bool)saveCapturedMedia saveEditedPhotos:(bool)saveEditedPhotos;
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -38,10 +38,11 @@ typedef enum
|
|||||||
@property (nonatomic, readonly) UIImage *badge;
|
@property (nonatomic, readonly) UIImage *badge;
|
||||||
@property (nonatomic, readonly) UIColor *badgeTextColor;
|
@property (nonatomic, readonly) UIColor *badgeTextColor;
|
||||||
@property (nonatomic, readonly) UIImage *sendIconImage;
|
@property (nonatomic, readonly) UIImage *sendIconImage;
|
||||||
|
@property (nonatomic, readonly) UIImage *doneIconImage;
|
||||||
|
|
||||||
@property (nonatomic, readonly) UIColor *maybeAccentColor;
|
@property (nonatomic, readonly) UIColor *maybeAccentColor;
|
||||||
|
|
||||||
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage maybeAccentColor:(UIColor *)maybeAccentColor;
|
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage doneIconImage:(UIImage *)doneIconImage maybeAccentColor:(UIColor *)maybeAccentColor;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
@class PGCameraShotMetadata;
|
@class PGCameraShotMetadata;
|
||||||
@class TGSuggestionContext;
|
@class TGSuggestionContext;
|
||||||
@class TGPhotoEditorController;
|
@class TGPhotoEditorController;
|
||||||
|
@class AVPlayer;
|
||||||
|
|
||||||
@protocol TGPhotoPaintStickersContext;
|
@protocol TGPhotoPaintStickersContext;
|
||||||
@class TGPhotoEntitiesContainerView;
|
@class TGPhotoEntitiesContainerView;
|
||||||
@ -57,6 +58,10 @@ typedef enum {
|
|||||||
@property (nonatomic, strong) PGCameraShotMetadata *metadata;
|
@property (nonatomic, strong) PGCameraShotMetadata *metadata;
|
||||||
@property (nonatomic, strong) NSArray *faces;
|
@property (nonatomic, strong) NSArray *faces;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSArray *cachedVideoThumbnails;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) AVPlayer *player;
|
||||||
|
|
||||||
@property (nonatomic, strong) TGPhotoEntitiesContainerView *entitiesView;
|
@property (nonatomic, strong) TGPhotoEntitiesContainerView *entitiesView;
|
||||||
|
|
||||||
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id<TGMediaEditableItem>)item intent:(TGPhotoEditorControllerIntent)intent adjustments:(id<TGMediaEditAdjustments>)adjustments caption:(NSString *)caption screenImage:(UIImage *)screenImage availableTabs:(TGPhotoEditorTab)availableTabs selectedTab:(TGPhotoEditorTab)selectedTab;
|
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id<TGMediaEditableItem>)item intent:(TGPhotoEditorControllerIntent)intent adjustments:(id<TGMediaEditAdjustments>)adjustments caption:(NSString *)caption screenImage:(UIImage *)screenImage availableTabs:(TGPhotoEditorTab)availableTabs selectedTab:(TGPhotoEditorTab)selectedTab;
|
||||||
|
|||||||
@ -63,6 +63,7 @@
|
|||||||
|
|
||||||
- (bool)isDismissAllowed;
|
- (bool)isDismissAllowed;
|
||||||
|
|
||||||
|
- (bool)hasOnScreenNavigation;
|
||||||
- (UIInterfaceOrientation)effectiveOrientation;
|
- (UIInterfaceOrientation)effectiveOrientation;
|
||||||
- (UIInterfaceOrientation)effectiveOrientation:(UIInterfaceOrientation)orientation;
|
- (UIInterfaceOrientation)effectiveOrientation:(UIInterfaceOrientation)orientation;
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,8 @@ typedef enum
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
TGPhotoEditorDoneButtonSend,
|
TGPhotoEditorDoneButtonSend,
|
||||||
TGPhotoEditorDoneButtonCheck
|
TGPhotoEditorDoneButtonCheck,
|
||||||
|
TGPhotoEditorDoneButtonDone
|
||||||
} TGPhotoEditorDoneButton;
|
} TGPhotoEditorDoneButton;
|
||||||
|
|
||||||
@interface TGPhotoToolbarView : UIView
|
@interface TGPhotoToolbarView : UIView
|
||||||
@ -47,6 +48,9 @@ typedef enum
|
|||||||
@property (nonatomic, readonly) CGRect cancelButtonFrame;
|
@property (nonatomic, readonly) CGRect cancelButtonFrame;
|
||||||
@property (nonatomic, readonly) CGRect doneButtonFrame;
|
@property (nonatomic, readonly) CGRect doneButtonFrame;
|
||||||
|
|
||||||
|
@property (nonatomic, assign) TGPhotoEditorBackButton backButtonType;
|
||||||
|
@property (nonatomic, assign) TGPhotoEditorDoneButton doneButtonType;
|
||||||
|
|
||||||
- (instancetype)initWithBackButton:(TGPhotoEditorBackButton)backButton doneButton:(TGPhotoEditorDoneButton)doneButton solidBackground:(bool)solidBackground;
|
- (instancetype)initWithBackButton:(TGPhotoEditorBackButton)backButton doneButton:(TGPhotoEditorDoneButton)doneButton solidBackground:(bool)solidBackground;
|
||||||
|
|
||||||
- (void)transitionInAnimated:(bool)animated;
|
- (void)transitionInAnimated:(bool)animated;
|
||||||
|
|||||||
@ -384,7 +384,7 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus";
|
|||||||
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
|
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
|
||||||
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
||||||
|
|
||||||
if (self.cameraMode == PGCameraModeSquarePhoto || self.cameraMode == PGCameraModeSquareVideo)
|
if (self.cameraMode == PGCameraModeSquarePhoto || self.cameraMode == PGCameraModeSquareVideo || self.cameraMode == PGCameraModeSquareSwing)
|
||||||
{
|
{
|
||||||
CGFloat shorterSide = MIN(image.size.width, image.size.height);
|
CGFloat shorterSide = MIN(image.size.width, image.size.height);
|
||||||
CGFloat longerSide = MAX(image.size.width, image.size.height);
|
CGFloat longerSide = MAX(image.size.width, image.size.height);
|
||||||
@ -636,7 +636,7 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus";
|
|||||||
|
|
||||||
- (bool)flashActive
|
- (bool)flashActive
|
||||||
{
|
{
|
||||||
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo)
|
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo || self.cameraMode == PGCameraModeSquareSwing)
|
||||||
return self.captureSession.videoDevice.torchActive;
|
return self.captureSession.videoDevice.torchActive;
|
||||||
|
|
||||||
return self.captureSession.videoDevice.flashActive;
|
return self.captureSession.videoDevice.flashActive;
|
||||||
@ -644,7 +644,7 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus";
|
|||||||
|
|
||||||
- (bool)flashAvailable
|
- (bool)flashAvailable
|
||||||
{
|
{
|
||||||
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo)
|
if (self.cameraMode == PGCameraModeVideo || self.cameraMode == PGCameraModeSquareVideo || self.cameraMode == PGCameraModeSquareSwing)
|
||||||
return self.captureSession.videoDevice.torchAvailable;
|
return self.captureSession.videoDevice.torchAvailable;
|
||||||
|
|
||||||
return self.captureSession.videoDevice.flashAvailable;
|
return self.captureSession.videoDevice.flashAvailable;
|
||||||
|
|||||||
@ -188,7 +188,7 @@ const NSInteger PGCameraFrameRate = 30;
|
|||||||
if (self.currentCameraPosition != _preferredCameraPosition)
|
if (self.currentCameraPosition != _preferredCameraPosition)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo)
|
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo || self.currentMode == PGCameraModeSquareSwing)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (self.zoomLevel > FLT_EPSILON)
|
if (self.zoomLevel > FLT_EPSILON)
|
||||||
@ -270,11 +270,12 @@ const NSInteger PGCameraFrameRate = 30;
|
|||||||
|
|
||||||
case PGCameraModeVideo:
|
case PGCameraModeVideo:
|
||||||
case PGCameraModeSquareVideo:
|
case PGCameraModeSquareVideo:
|
||||||
|
case PGCameraModeSquareSwing:
|
||||||
{
|
{
|
||||||
self.sessionPreset = AVCaptureSessionPresetInputPriority;
|
self.sessionPreset = AVCaptureSessionPresetInputPriority;
|
||||||
[self switchToBestVideoFormatForDevice:_videoDevice];
|
[self switchToBestVideoFormatForDevice:_videoDevice];
|
||||||
[self _addAudioInputRequestAudioSession:true];
|
[self _addAudioInputRequestAudioSession:true];
|
||||||
[self setFrameRate:PGCameraFrameRate forDevice:_videoDevice];
|
[self setFrameRate:mode == PGCameraFrameRate forDevice:_videoDevice];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -529,6 +530,7 @@ const NSInteger PGCameraFrameRate = 30;
|
|||||||
{
|
{
|
||||||
case PGCameraModeVideo:
|
case PGCameraModeVideo:
|
||||||
case PGCameraModeSquareVideo:
|
case PGCameraModeSquareVideo:
|
||||||
|
case PGCameraModeSquareSwing:
|
||||||
return _videoFlashMode;
|
return _videoFlashMode;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -544,6 +546,7 @@ const NSInteger PGCameraFrameRate = 30;
|
|||||||
{
|
{
|
||||||
case PGCameraModeVideo:
|
case PGCameraModeVideo:
|
||||||
case PGCameraModeSquareVideo:
|
case PGCameraModeSquareVideo:
|
||||||
|
case PGCameraModeSquareSwing:
|
||||||
{
|
{
|
||||||
AVCaptureTorchMode torchMode = [PGCameraCaptureSession _deviceTorchModeForCameraFlashMode:mode];
|
AVCaptureTorchMode torchMode = [PGCameraCaptureSession _deviceTorchModeForCameraFlashMode:mode];
|
||||||
if (device.hasTorch && [device isTorchModeSupported:torchMode])
|
if (device.hasTorch && [device isTorchModeSupported:torchMode])
|
||||||
@ -660,7 +663,7 @@ const NSInteger PGCameraFrameRate = 30;
|
|||||||
|
|
||||||
[self commitConfiguration];
|
[self commitConfiguration];
|
||||||
|
|
||||||
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo)
|
if (self.currentMode == PGCameraModeVideo || self.currentMode == PGCameraModeSquareVideo || self.currentMode == PGCameraModeSquareSwing)
|
||||||
[self setFrameRate:PGCameraFrameRate forDevice:deviceForTargetPosition];
|
[self setFrameRate:PGCameraFrameRate forDevice:deviceForTargetPosition];
|
||||||
else
|
else
|
||||||
[self setFrameRate:0 forDevice:deviceForTargetPosition];
|
[self setFrameRate:0 forDevice:deviceForTargetPosition];
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#import "PGPhotoBlurPass.h"
|
#import "PGPhotoBlurPass.h"
|
||||||
|
|
||||||
#import "GPUImageTwoInputFilter.h"
|
#import "GPUImageTwoInputFilter.h"
|
||||||
|
#import "GPUImageThreeInputFilter.h"
|
||||||
#import "PGPhotoGaussianBlurFilter.h"
|
#import "PGPhotoGaussianBlurFilter.h"
|
||||||
|
|
||||||
NSString *const PGPhotoRadialBlurShaderString = PGShaderString
|
NSString *const PGPhotoRadialBlurShaderString = PGShaderString
|
||||||
@ -54,12 +55,33 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
NSString *const PGPhotoMaskedBlurShaderString = PGShaderString
|
||||||
|
(
|
||||||
|
varying highp vec2 texCoord;
|
||||||
|
varying highp vec2 texCoord2;
|
||||||
|
varying highp vec2 texCoord3;
|
||||||
|
|
||||||
|
uniform sampler2D sourceImage;
|
||||||
|
uniform sampler2D inputImageTexture2;
|
||||||
|
uniform sampler2D inputImageTexture3;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
lowp vec4 sharpImageColor = texture2D(sourceImage, texCoord);
|
||||||
|
lowp vec4 blurredImageColor = texture2D(inputImageTexture2, texCoord2);
|
||||||
|
lowp vec4 maskImageColor = texture2D(inputImageTexture3, texCoord3);
|
||||||
|
|
||||||
|
gl_FragColor = mix(blurredImageColor, sharpImageColor, maskImageColor.r);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
@interface PGPhotoBlurFilter : GPUImageOutput <GPUImageInput>
|
@interface PGPhotoBlurFilter : GPUImageOutput <GPUImageInput>
|
||||||
{
|
{
|
||||||
PGPhotoGaussianBlurFilter *_blurFilter;
|
PGPhotoGaussianBlurFilter *_blurFilter;
|
||||||
|
|
||||||
GPUImageTwoInputFilter *_radialFocusFilter;
|
GPUImageTwoInputFilter *_radialFocusFilter;
|
||||||
GPUImageTwoInputFilter *_linearFocusFilter;
|
GPUImageTwoInputFilter *_linearFocusFilter;
|
||||||
|
GPUImageThreeInputFilter *_maskedFilter;
|
||||||
|
|
||||||
GPUImageOutput <GPUImageInput> *_currentFocusFilter;
|
GPUImageOutput <GPUImageInput> *_currentFocusFilter;
|
||||||
|
|
||||||
@ -104,6 +126,10 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PGBlurToolTypePortrait:
|
||||||
|
{
|
||||||
|
_currentFocusFilter = _maskedFilter;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -192,6 +218,7 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
|||||||
[_blurFilter setInputSize:newSize atIndex:textureIndex];
|
[_blurFilter setInputSize:newSize atIndex:textureIndex];
|
||||||
[_radialFocusFilter setInputSize:newSize atIndex:textureIndex];
|
[_radialFocusFilter setInputSize:newSize atIndex:textureIndex];
|
||||||
[_linearFocusFilter setInputSize:newSize atIndex:textureIndex];
|
[_linearFocusFilter setInputSize:newSize atIndex:textureIndex];
|
||||||
|
[_maskedFilter setInputSize:newSize atIndex:textureIndex];
|
||||||
|
|
||||||
CGFloat aspectRatio = newSize.height / newSize.width;
|
CGFloat aspectRatio = newSize.height / newSize.width;
|
||||||
[_radialFocusFilter setFloat:(float)aspectRatio forUniformName:@"aspectRatio"];
|
[_radialFocusFilter setFloat:(float)aspectRatio forUniformName:@"aspectRatio"];
|
||||||
@ -203,6 +230,7 @@ NSString *const PGPhotoLinearBlurShaderString = PGShaderString
|
|||||||
[_blurFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
[_blurFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||||
[_radialFocusFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
[_radialFocusFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||||
[_linearFocusFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
[_linearFocusFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||||
|
[_maskedFilter setInputRotation:newInputRotation atIndex:textureIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGSize)maximumOutputSize
|
- (CGSize)maximumOutputSize
|
||||||
|
|||||||
@ -937,7 +937,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
|
|||||||
{
|
{
|
||||||
if (editableItem.isVideo) {
|
if (editableItem.isVideo) {
|
||||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -921,6 +921,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
|
|
||||||
case PGCameraModeVideo:
|
case PGCameraModeVideo:
|
||||||
case PGCameraModeSquareVideo:
|
case PGCameraModeSquareVideo:
|
||||||
|
case PGCameraModeSquareSwing:
|
||||||
{
|
{
|
||||||
if (!_camera.isRecordingVideo)
|
if (!_camera.isRecordingVideo)
|
||||||
{
|
{
|
||||||
@ -994,7 +995,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
else if (cameraMode == PGCameraModeVideo)
|
else if (cameraMode == PGCameraModeVideo || cameraMode == PGCameraModeSquareVideo || cameraMode == PGCameraModeSquareSwing)
|
||||||
{
|
{
|
||||||
if (!_camera.isRecordingVideo)
|
if (!_camera.isRecordingVideo)
|
||||||
{
|
{
|
||||||
@ -1009,14 +1010,18 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
TGCameraCapturedVideo *capturedVideo = [[TGCameraCapturedVideo alloc] initWithURL:outputURL];
|
TGCameraCapturedVideo *capturedVideo = [[TGCameraCapturedVideo alloc] initWithURL:outputURL];
|
||||||
|
if (strongSelf->_intent == TGCameraControllerAvatarIntent || strongSelf->_intent == TGCameraControllerSignupAvatarIntent)
|
||||||
|
{
|
||||||
|
[strongSelf presentPhotoResultControllerWithImage:capturedVideo metadata:nil completion:^{}];
|
||||||
|
} else {
|
||||||
[strongSelf addResultItem:capturedVideo];
|
[strongSelf addResultItem:capturedVideo];
|
||||||
|
|
||||||
if (![strongSelf maybePresentResultControllerForItem:capturedVideo completion:nil])
|
if (![strongSelf maybePresentResultControllerForItem:capturedVideo completion:nil])
|
||||||
{
|
{
|
||||||
strongSelf->_camera.disabled = false;
|
strongSelf->_camera.disabled = false;
|
||||||
[strongSelf->_interfaceView setRecordingVideo:false animated:true];
|
[strongSelf->_interfaceView setRecordingVideo:false animated:true];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[strongSelf->_interfaceView setRecordingVideo:false animated:false];
|
[strongSelf->_interfaceView setRecordingVideo:false animated:false];
|
||||||
@ -1655,16 +1660,30 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
|
|
||||||
#pragma mark - Legacy Photo Result
|
#pragma mark - Legacy Photo Result
|
||||||
|
|
||||||
- (void)presentPhotoResultControllerWithImage:(UIImage *)image metadata:(PGCameraShotMetadata *)metadata completion:(void (^)(void))completion
|
- (void)presentPhotoResultControllerWithImage:(id<TGMediaEditableItem>)input metadata:(PGCameraShotMetadata *)metadata completion:(void (^)(void))completion
|
||||||
{
|
{
|
||||||
[[[LegacyComponentsGlobals provider] applicationInstance] setIdleTimerDisabled:false];
|
[[[LegacyComponentsGlobals provider] applicationInstance] setIdleTimerDisabled:false];
|
||||||
|
|
||||||
if (image == nil || image.size.width < FLT_EPSILON)
|
if (input == nil || ([input isKindOfClass:[UIImage class]] && ((UIImage *)input).size.width < FLT_EPSILON))
|
||||||
{
|
{
|
||||||
[self beginTransitionOutWithVelocity:0.0f];
|
[self beginTransitionOutWithVelocity:0.0f];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIImage *image = nil;
|
||||||
|
if ([input isKindOfClass:[UIImage class]]) {
|
||||||
|
image = (UIImage *)input;
|
||||||
|
} else if ([input isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||||
|
AVAsset *asset = ((TGCameraCapturedVideo *)input).immediateAVAsset;
|
||||||
|
|
||||||
|
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
|
||||||
|
generator.appliesPreferredTrackTransform = true;
|
||||||
|
generator.maximumSize = CGSizeMake(640.0f, 640.0f);
|
||||||
|
CGImageRef imageRef = [generator copyCGImageAtTime:kCMTimeZero actualTime:NULL error:NULL];
|
||||||
|
image = [[UIImage alloc] initWithCGImage:imageRef];
|
||||||
|
CGImageRelease(imageRef);
|
||||||
|
}
|
||||||
|
|
||||||
id<LegacyComponentsOverlayWindowManager> windowManager = nil;
|
id<LegacyComponentsOverlayWindowManager> windowManager = nil;
|
||||||
id<LegacyComponentsContext> windowContext = nil;
|
id<LegacyComponentsContext> windowContext = nil;
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
|
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
|
||||||
@ -1679,16 +1698,11 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
|
|
||||||
_focusControl.ignoreAutofocusing = true;
|
_focusControl.ignoreAutofocusing = true;
|
||||||
|
|
||||||
switch (_intent)
|
|
||||||
{
|
|
||||||
case TGCameraControllerAvatarIntent:
|
|
||||||
case TGCameraControllerSignupAvatarIntent:
|
|
||||||
{
|
|
||||||
TGPhotoEditorControllerIntent intent = TGPhotoEditorControllerAvatarIntent;
|
TGPhotoEditorControllerIntent intent = TGPhotoEditorControllerAvatarIntent;
|
||||||
if (_intent == TGCameraControllerSignupAvatarIntent) {
|
if (_intent == TGCameraControllerSignupAvatarIntent) {
|
||||||
intent = TGPhotoEditorControllerSignupAvatarIntent;
|
intent = TGPhotoEditorControllerSignupAvatarIntent;
|
||||||
}
|
}
|
||||||
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:windowContext item:image intent:(TGPhotoEditorControllerFromCameraIntent | intent) adjustments:nil caption:nil screenImage:image availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab];
|
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:windowContext item:input intent:(TGPhotoEditorControllerFromCameraIntent | intent) adjustments:nil caption:nil screenImage:image availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab];
|
||||||
controller.stickersContext = _stickersContext;
|
controller.stickersContext = _stickersContext;
|
||||||
__weak TGPhotoEditorController *weakController = controller;
|
__weak TGPhotoEditorController *weakController = controller;
|
||||||
controller.beginTransitionIn = ^UIView *(CGRect *referenceFrame, __unused UIView **parentView)
|
controller.beginTransitionIn = ^UIView *(CGRect *referenceFrame, __unused UIView **parentView)
|
||||||
@ -1738,7 +1752,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
if (strongSelf.finishedWithPhoto != nil)
|
if (strongSelf.finishedWithPhoto != nil)
|
||||||
strongSelf.finishedWithPhoto(nil, resultImage, nil, nil, nil, nil);
|
strongSelf.finishedWithPhoto(nil, resultImage, nil, nil, nil, nil);
|
||||||
|
|
||||||
if (strongSelf.shouldStoreCapturedAssets)
|
if (strongSelf.shouldStoreCapturedAssets && [input isKindOfClass:[UIImage class]])
|
||||||
{
|
{
|
||||||
[strongSelf _savePhotoToCameraRollWithOriginalImage:image editedImage:[editorValues toolsApplied] ? resultImage : nil];
|
[strongSelf _savePhotoToCameraRollWithOriginalImage:image editedImage:[editorValues toolsApplied] ? resultImage : nil];
|
||||||
}
|
}
|
||||||
@ -1766,7 +1780,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
{
|
{
|
||||||
if (editableItem.isVideo) {
|
if (editableItem.isVideo) {
|
||||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||||
} else {
|
} else {
|
||||||
@ -1778,79 +1792,6 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
};
|
};
|
||||||
|
|
||||||
overlayController = (TGOverlayController *)controller;
|
overlayController = (TGOverlayController *)controller;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
TGCameraPhotoPreviewController *controller = _shortcut ? [[TGCameraPhotoPreviewController alloc] initWithContext:windowContext image:image metadata:metadata recipientName:self.recipientName backButtonTitle:TGLocalized(@"Camera.Retake") doneButtonTitle:TGLocalized(@"Common.Next") saveCapturedMedia:_saveCapturedMedia saveEditedPhotos:_saveEditedPhotos] : [[TGCameraPhotoPreviewController alloc] initWithContext:windowContext image:image metadata:metadata recipientName:self.recipientName saveCapturedMedia:_saveCapturedMedia saveEditedPhotos:_saveEditedPhotos];
|
|
||||||
controller.allowCaptions = self.allowCaptions;
|
|
||||||
controller.shouldStoreAssets = self.shouldStoreCapturedAssets;
|
|
||||||
controller.suggestionContext = self.suggestionContext;
|
|
||||||
controller.hasTimer = self.hasTimer;
|
|
||||||
controller.hasSilentPosting = self.hasSilentPosting;
|
|
||||||
controller.hasSchedule = self.hasSchedule;
|
|
||||||
|
|
||||||
__weak TGCameraPhotoPreviewController *weakController = controller;
|
|
||||||
controller.beginTransitionIn = ^CGRect
|
|
||||||
{
|
|
||||||
__strong TGCameraController *strongSelf = weakSelf;
|
|
||||||
if (strongSelf == nil)
|
|
||||||
return CGRectZero;
|
|
||||||
|
|
||||||
strongSelf->_previewView.hidden = true;
|
|
||||||
|
|
||||||
return strongSelf->_previewView.frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.finishedTransitionIn = ^
|
|
||||||
{
|
|
||||||
__strong TGCameraController *strongSelf = weakSelf;
|
|
||||||
if (strongSelf != nil)
|
|
||||||
[strongSelf->_camera stopCaptureForPause:true completion:nil];
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.beginTransitionOut = ^CGRect(CGRect referenceFrame)
|
|
||||||
{
|
|
||||||
__strong TGCameraController *strongSelf = weakSelf;
|
|
||||||
if (strongSelf == nil)
|
|
||||||
return CGRectZero;
|
|
||||||
|
|
||||||
[strongSelf->_camera startCaptureForResume:true completion:nil];
|
|
||||||
|
|
||||||
return [strongSelf transitionBackFromResultControllerWithReferenceFrame:referenceFrame];
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.retakePressed = ^
|
|
||||||
{
|
|
||||||
__strong TGCameraController *strongSelf = weakSelf;
|
|
||||||
if (strongSelf == nil)
|
|
||||||
return;
|
|
||||||
|
|
||||||
[[[LegacyComponentsGlobals provider] applicationInstance] setIdleTimerDisabled:true];
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.sendPressed = ^(TGOverlayController *controller, UIImage *resultImage, NSString *caption, NSArray *entities, NSArray *stickers, NSNumber *timer)
|
|
||||||
{
|
|
||||||
__strong TGCameraController *strongSelf = weakSelf;
|
|
||||||
if (strongSelf == nil)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (strongSelf.finishedWithPhoto != nil)
|
|
||||||
strongSelf.finishedWithPhoto(controller, resultImage, caption, entities, stickers, timer);
|
|
||||||
|
|
||||||
if (strongSelf->_shortcut)
|
|
||||||
return;
|
|
||||||
|
|
||||||
__strong TGOverlayController *strongController = weakController;
|
|
||||||
if (strongController != nil)
|
|
||||||
[strongSelf _dismissTransitionForResultController:strongController];
|
|
||||||
};
|
|
||||||
|
|
||||||
overlayController = controller;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (windowManager != nil)
|
if (windowManager != nil)
|
||||||
{
|
{
|
||||||
@ -2375,6 +2316,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
|
|
||||||
case PGCameraModeSquarePhoto:
|
case PGCameraModeSquarePhoto:
|
||||||
case PGCameraModeSquareVideo:
|
case PGCameraModeSquareVideo:
|
||||||
|
case PGCameraModeSquareSwing:
|
||||||
{
|
{
|
||||||
CGRect rect = [self _cameraPreviewFrameForScreenSize:screenSize mode:PGCameraModePhoto];
|
CGRect rect = [self _cameraPreviewFrameForScreenSize:screenSize mode:PGCameraModePhoto];
|
||||||
CGFloat topOffset = CGRectGetMidY(rect) - rect.size.width / 2;
|
CGFloat topOffset = CGRectGetMidY(rect) - rect.size.width / 2;
|
||||||
@ -2406,7 +2348,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mode == PGCameraModeSquarePhoto || mode == PGCameraModeSquareVideo)
|
if (mode == PGCameraModeSquarePhoto || mode == PGCameraModeSquareVideo || mode == PGCameraModeSquareSwing)
|
||||||
return CGRectMake(0, (screenSize.height - screenSize.width) / 2, screenSize.width, screenSize.width);
|
return CGRectMake(0, (screenSize.height - screenSize.width) / 2, screenSize.width, screenSize.width);
|
||||||
|
|
||||||
return CGRectMake(0, 0, screenSize.width, screenSize.height);
|
return CGRectMake(0, 0, screenSize.width, screenSize.height);
|
||||||
|
|||||||
@ -50,17 +50,17 @@
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PGCameraModeVideo:
|
case PGCameraModeVideo:
|
||||||
|
case PGCameraModeSquareVideo:
|
||||||
{
|
{
|
||||||
[_shutterButton setButtonMode:TGCameraShutterButtonVideoMode animated:true];
|
[_shutterButton setButtonMode:TGCameraShutterButtonVideoMode animated:true];
|
||||||
[_timecodeView setHidden:false animated:true];
|
[_timecodeView setHidden:false animated:true];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PGCameraModeSquareVideo:
|
case PGCameraModeSquareSwing:
|
||||||
{
|
{
|
||||||
[_shutterButton setButtonMode:TGCameraShutterButtonVideoMode animated:true];
|
[_shutterButton setButtonMode:TGCameraShutterButtonVideoMode animated:true];
|
||||||
[_timecodeView setHidden:true animated:true];
|
[_timecodeView setHidden:true animated:true];
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
|||||||
|
|
||||||
@interface TGCameraModeControl ()
|
@interface TGCameraModeControl ()
|
||||||
{
|
{
|
||||||
UIImageView *_dotView;
|
|
||||||
UIControl *_wrapperView;
|
UIControl *_wrapperView;
|
||||||
|
|
||||||
CGFloat _kerning;
|
CGFloat _kerning;
|
||||||
@ -27,24 +26,6 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
|||||||
self = [super initWithFrame:frame];
|
self = [super initWithFrame:frame];
|
||||||
if (self != nil)
|
if (self != nil)
|
||||||
{
|
{
|
||||||
static UIImage *dotImage = nil;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^
|
|
||||||
{
|
|
||||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(6, 6), false, 0.0f);
|
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
||||||
|
|
||||||
CGContextSetFillColorWithColor(context, [TGCameraInterfaceAssets accentColor].CGColor);
|
|
||||||
CGContextFillEllipseInRect(context, CGRectMake(0, 0, 6, 6));
|
|
||||||
|
|
||||||
dotImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
||||||
UIGraphicsEndImageContext();
|
|
||||||
});
|
|
||||||
|
|
||||||
_dotView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 6, 6)];
|
|
||||||
_dotView.image = dotImage;
|
|
||||||
//[self addSubview:_dotView];
|
|
||||||
|
|
||||||
if (frame.size.width > frame.size.height)
|
if (frame.size.width > frame.size.height)
|
||||||
_kerning = 3.5f;
|
_kerning = 3.5f;
|
||||||
else
|
else
|
||||||
@ -64,7 +45,8 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
|||||||
_buttons = @
|
_buttons = @
|
||||||
[
|
[
|
||||||
[self _createButtonForMode:PGCameraModeSquareVideo title:TGLocalized(@"Camera.VideoMode")],
|
[self _createButtonForMode:PGCameraModeSquareVideo title:TGLocalized(@"Camera.VideoMode")],
|
||||||
[self _createButtonForMode:PGCameraModePhoto title:TGLocalized(@"Camera.PhotoMode")]
|
[self _createButtonForMode:PGCameraModePhoto title:TGLocalized(@"Camera.PhotoMode")],
|
||||||
|
[self _createButtonForMode:PGCameraModeSquareSwing title:@"SWING"]
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
_buttons = @
|
_buttons = @
|
||||||
@ -119,7 +101,6 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
|||||||
|
|
||||||
+ (CGFloat)_buttonHorizontalSpacing
|
+ (CGFloat)_buttonHorizontalSpacing
|
||||||
{
|
{
|
||||||
//return 22;
|
|
||||||
return 19;
|
return 19;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,14 +263,7 @@ const CGFloat TGCameraModeControlVerticalInteritemSpace = 29.0f;
|
|||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
if (self.frame.size.width > self.frame.size.height)
|
if (self.frame.size.width > self.frame.size.height)
|
||||||
{
|
|
||||||
_dotView.frame = CGRectMake((self.frame.size.width - _dotView.frame.size.width) / 2, self.frame.size.height / 2 - 12, _dotView.frame.size.width, _dotView.frame.size.height);
|
|
||||||
_maskLayer.frame = CGRectMake(0, 0, _maskView.frame.size.width, _maskView.frame.size.height);
|
_maskLayer.frame = CGRectMake(0, 0, _maskView.frame.size.width, _maskView.frame.size.height);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_dotView.frame = CGRectMake(13, (self.frame.size.height - _dotView.frame.size.height) / 2, _dotView.frame.size.width, _dotView.frame.size.height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1374,7 +1374,7 @@
|
|||||||
|
|
||||||
@implementation TGMediaAssetsPallete
|
@implementation TGMediaAssetsPallete
|
||||||
|
|
||||||
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage maybeAccentColor:(UIColor *)maybeAccentColor
|
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor navigationTitleColor:(UIColor *)navigationTitleColor badge:(UIImage *)badge badgeTextColor:(UIColor *)badgeTextColor sendIconImage:(UIImage *)sendIconImage doneIconImage:(UIImage *)doneIconImage maybeAccentColor:(UIColor *)maybeAccentColor
|
||||||
{
|
{
|
||||||
TGMediaAssetsPallete *pallete = [[TGMediaAssetsPallete alloc] init];
|
TGMediaAssetsPallete *pallete = [[TGMediaAssetsPallete alloc] init];
|
||||||
pallete->_isDark = dark;
|
pallete->_isDark = dark;
|
||||||
@ -1390,6 +1390,7 @@
|
|||||||
pallete->_badge = badge;
|
pallete->_badge = badge;
|
||||||
pallete->_badgeTextColor = badgeTextColor;
|
pallete->_badgeTextColor = badgeTextColor;
|
||||||
pallete->_sendIconImage = sendIconImage;
|
pallete->_sendIconImage = sendIconImage;
|
||||||
|
pallete->_doneIconImage = doneIconImage;
|
||||||
pallete->_maybeAccentColor = maybeAccentColor;
|
pallete->_maybeAccentColor = maybeAccentColor;
|
||||||
return pallete;
|
return pallete;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -441,7 +441,7 @@
|
|||||||
{
|
{
|
||||||
if (editableItem.isVideo) {
|
if (editableItem.isVideo) {
|
||||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -94,6 +94,7 @@
|
|||||||
{
|
{
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
TGPhotoEditorController *controller = _controller;
|
||||||
void (^imageReady)(void) = self.imageReady;
|
void (^imageReady)(void) = self.imageReady;
|
||||||
_toTransitionView = [[TGImageView alloc] initWithFrame:fromTransitionFrame];
|
_toTransitionView = [[TGImageView alloc] initWithFrame:fromTransitionFrame];
|
||||||
[_toTransitionView setSignal:[[[self.referenceScreenImageSignal() deliverOn:[SQueue mainQueue]] filter:^bool(id result)
|
[_toTransitionView setSignal:[[[self.referenceScreenImageSignal() deliverOn:[SQueue mainQueue]] filter:^bool(id result)
|
||||||
@ -101,7 +102,7 @@
|
|||||||
return [result isKindOfClass:[UIImage class]];
|
return [result isKindOfClass:[UIImage class]];
|
||||||
}] onNext:^(UIImage *next)
|
}] onNext:^(UIImage *next)
|
||||||
{
|
{
|
||||||
[_controller _setScreenImage:next];
|
[controller _setScreenImage:next];
|
||||||
if (imageReady != nil)
|
if (imageReady != nil)
|
||||||
imageReady();
|
imageReady();
|
||||||
}]];
|
}]];
|
||||||
|
|||||||
@ -577,7 +577,7 @@
|
|||||||
{
|
{
|
||||||
if (editableItem.isVideo) {
|
if (editableItem.isVideo) {
|
||||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
|
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -15,11 +15,12 @@
|
|||||||
@property (nonatomic, assign) NSTimeInterval trimStartValue;
|
@property (nonatomic, assign) NSTimeInterval trimStartValue;
|
||||||
@property (nonatomic, assign) NSTimeInterval trimEndValue;
|
@property (nonatomic, assign) NSTimeInterval trimEndValue;
|
||||||
|
|
||||||
@property (nonatomic, assign) NSTimeInterval dotValue;
|
@property (nonatomic, assign) bool hasDotPicker;
|
||||||
|
- (void)setDotVideoView:(UIView *)dotVideoView;
|
||||||
|
- (void)setDotImage:(UIImage *)dotImage;
|
||||||
|
|
||||||
@property (nonatomic, assign) NSTimeInterval maximumLength;
|
@property (nonatomic, assign) NSTimeInterval maximumLength;
|
||||||
|
|
||||||
|
|
||||||
@property (nonatomic, assign) bool disableZoom;
|
@property (nonatomic, assign) bool disableZoom;
|
||||||
@property (nonatomic, assign) bool disableTimeDisplay;
|
@property (nonatomic, assign) bool disableTimeDisplay;
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,10 @@ typedef enum
|
|||||||
UIView *_rightCurtainView;
|
UIView *_rightCurtainView;
|
||||||
UIControl *_scrubberHandle;
|
UIControl *_scrubberHandle;
|
||||||
|
|
||||||
UIImageView *_dotView;
|
UIControl *_dotHandle;
|
||||||
|
UIImageView *_dotImageView;
|
||||||
|
__weak UIView *_dotVideoView;
|
||||||
|
UIImageView *_dotFrameView;
|
||||||
|
|
||||||
UIPanGestureRecognizer *_panGestureRecognizer;
|
UIPanGestureRecognizer *_panGestureRecognizer;
|
||||||
UILongPressGestureRecognizer *_pressGestureRecognizer;
|
UILongPressGestureRecognizer *_pressGestureRecognizer;
|
||||||
@ -126,11 +129,6 @@ typedef enum
|
|||||||
_rightCurtainView.backgroundColor = [[TGPhotoEditorInterfaceAssets toolbarBackgroundColor] colorWithAlphaComponent:0.8f];
|
_rightCurtainView.backgroundColor = [[TGPhotoEditorInterfaceAssets toolbarBackgroundColor] colorWithAlphaComponent:0.8f];
|
||||||
[_wrapperView addSubview:_rightCurtainView];
|
[_wrapperView addSubview:_rightCurtainView];
|
||||||
|
|
||||||
_dotView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 8, 8)];
|
|
||||||
_dotView.image = TGCircleImage(8.0, [TGPhotoEditorInterfaceAssets accentColor]);
|
|
||||||
_dotView.hidden = true;
|
|
||||||
[self addSubview:_dotView];
|
|
||||||
|
|
||||||
__weak TGMediaPickerGalleryVideoScrubber *weakSelf = self;
|
__weak TGMediaPickerGalleryVideoScrubber *weakSelf = self;
|
||||||
_trimView = [[TGMediaPickerGalleryVideoTrimView alloc] initWithFrame:CGRectZero];
|
_trimView = [[TGMediaPickerGalleryVideoTrimView alloc] initWithFrame:CGRectZero];
|
||||||
_trimView.exclusiveTouch = true;
|
_trimView.exclusiveTouch = true;
|
||||||
@ -158,7 +156,11 @@ typedef enum
|
|||||||
|
|
||||||
[strongSelf->_trimView setTrimming:true animated:true];
|
[strongSelf->_trimView setTrimming:true animated:true];
|
||||||
|
|
||||||
|
if (strongSelf->_hasDotPicker) {
|
||||||
|
[strongSelf setDotHandleHidden:true animated:false];
|
||||||
|
} else {
|
||||||
[strongSelf setScrubberHandleHidden:true animated:false];
|
[strongSelf setScrubberHandleHidden:true animated:false];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
_trimView.didEndEditing = ^
|
_trimView.didEndEditing = ^
|
||||||
{
|
{
|
||||||
@ -206,7 +208,11 @@ typedef enum
|
|||||||
|
|
||||||
[strongSelf->_trimView setTrimming:isTrimmed animated:true];
|
[strongSelf->_trimView setTrimming:isTrimmed animated:true];
|
||||||
|
|
||||||
|
if (strongSelf->_hasDotPicker) {
|
||||||
|
[strongSelf setDotHandleHidden:false animated:true];
|
||||||
|
} else {
|
||||||
[strongSelf setScrubberHandleHidden:false animated:true];
|
[strongSelf setScrubberHandleHidden:false animated:true];
|
||||||
|
}
|
||||||
|
|
||||||
[strongSelf cancelZoomIn];
|
[strongSelf cancelZoomIn];
|
||||||
if (strongSelf->_zoomedIn)
|
if (strongSelf->_zoomedIn)
|
||||||
@ -260,8 +266,13 @@ typedef enum
|
|||||||
strongSelf->_trimStartValue = trimStartPosition;
|
strongSelf->_trimStartValue = trimStartPosition;
|
||||||
strongSelf->_trimEndValue = trimEndPosition;
|
strongSelf->_trimEndValue = trimEndPosition;
|
||||||
|
|
||||||
[strongSelf setValue:strongSelf->_trimStartValue];
|
if (strongSelf->_hasDotPicker) {
|
||||||
|
if (strongSelf->_value < trimStartPosition) {
|
||||||
|
strongSelf->_value = trimStartPosition;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[strongSelf setValue:trimStartPosition];
|
||||||
|
}
|
||||||
UIView *handle = strongSelf->_scrubberHandle;
|
UIView *handle = strongSelf->_scrubberHandle;
|
||||||
handle.center = CGPointMake(trimView.frame.origin.x + 12 + handle.frame.size.width / 2, handle.center.y);
|
handle.center = CGPointMake(trimView.frame.origin.x + 12 + handle.frame.size.width / 2, handle.center.y);
|
||||||
|
|
||||||
@ -323,7 +334,13 @@ typedef enum
|
|||||||
strongSelf->_trimStartValue = trimStartPosition;
|
strongSelf->_trimStartValue = trimStartPosition;
|
||||||
strongSelf->_trimEndValue = trimEndPosition;
|
strongSelf->_trimEndValue = trimEndPosition;
|
||||||
|
|
||||||
[strongSelf setValue:strongSelf->_trimEndValue];
|
if (strongSelf->_hasDotPicker) {
|
||||||
|
if (strongSelf->_value > trimEndPosition) {
|
||||||
|
strongSelf->_value = trimEndPosition;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[strongSelf setValue:trimEndPosition];
|
||||||
|
}
|
||||||
|
|
||||||
UIView *handle = strongSelf->_scrubberHandle;
|
UIView *handle = strongSelf->_scrubberHandle;
|
||||||
handle.center = CGPointMake(CGRectGetMaxX(trimView.frame) - 12 - handle.frame.size.width / 2, handle.center.y);
|
handle.center = CGPointMake(CGRectGetMaxX(trimView.frame) - 12 - handle.frame.size.width / 2, handle.center.y);
|
||||||
@ -341,13 +358,44 @@ typedef enum
|
|||||||
};
|
};
|
||||||
[_wrapperView addSubview:_trimView];
|
[_wrapperView addSubview:_trimView];
|
||||||
|
|
||||||
|
_dotHandle = [[UIControl alloc] initWithFrame:CGRectMake(0, -4.0f, 26.0f, 44.0f)];
|
||||||
|
_dotHandle.hitTestEdgeInsets = UIEdgeInsetsMake(-5, -12, -5, -12);
|
||||||
|
_dotHandle.hidden = true;
|
||||||
|
[_wrapperView addSubview:_dotHandle];
|
||||||
|
|
||||||
|
static UIImage *dotFrameImage = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^
|
||||||
|
{
|
||||||
|
UIGraphicsBeginImageContextWithOptions(CGSizeMake(_dotHandle.frame.size.width, _dotHandle.frame.size.height), false, 0.0f);
|
||||||
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
|
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
|
||||||
|
CGContextSetLineWidth(context, 3.0);
|
||||||
|
|
||||||
|
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(1.5f, 1.5f, _dotHandle.frame.size.width - 3.0, _dotHandle.frame.size.height - 3.0f) cornerRadius:4.0f];
|
||||||
|
CGContextAddPath(context, path.CGPath);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
|
dotFrameImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
|
UIGraphicsEndImageContext();
|
||||||
|
});
|
||||||
|
|
||||||
|
_dotImageView = [[UIImageView alloc] initWithFrame:CGRectInset(_dotHandle.bounds, 2.0, 2.0)];
|
||||||
|
_dotImageView.clipsToBounds = true;
|
||||||
|
_dotImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
|
[_dotHandle addSubview:_dotImageView];
|
||||||
|
|
||||||
|
_dotFrameView = [[UIImageView alloc] initWithFrame:_dotHandle.bounds];
|
||||||
|
_dotFrameView.image = dotFrameImage;
|
||||||
|
[_dotHandle addSubview:_dotFrameView];
|
||||||
|
|
||||||
_scrubberHandle = [[UIControl alloc] initWithFrame:CGRectMake(0, -4.0f, 5.0f, 44.0f)];
|
_scrubberHandle = [[UIControl alloc] initWithFrame:CGRectMake(0, -4.0f, 5.0f, 44.0f)];
|
||||||
_scrubberHandle.hitTestEdgeInsets = UIEdgeInsetsMake(-5, -12, -5, -12);
|
_scrubberHandle.hitTestEdgeInsets = UIEdgeInsetsMake(-5, -12, -5, -12);
|
||||||
[_wrapperView addSubview:_scrubberHandle];
|
[_wrapperView addSubview:_scrubberHandle];
|
||||||
|
|
||||||
static UIImage *handleViewImage = nil;
|
static UIImage *handleViewImage = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken2;
|
||||||
dispatch_once(&onceToken, ^
|
dispatch_once(&onceToken2, ^
|
||||||
{
|
{
|
||||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(_scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height), false, 0.0f);
|
UIGraphicsBeginImageContextWithOptions(CGSizeMake(_scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height), false, 0.0f);
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
@ -373,6 +421,7 @@ typedef enum
|
|||||||
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
|
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
|
||||||
_panGestureRecognizer.delegate = self;
|
_panGestureRecognizer.delegate = self;
|
||||||
[_scrubberHandle addGestureRecognizer:_panGestureRecognizer];
|
[_scrubberHandle addGestureRecognizer:_panGestureRecognizer];
|
||||||
|
[_dotHandle addGestureRecognizer:_panGestureRecognizer];
|
||||||
|
|
||||||
_arrowView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PhotoPickerArrow")];
|
_arrowView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PhotoPickerArrow")];
|
||||||
_arrowView.alpha = 0.45f;
|
_arrowView.alpha = 0.45f;
|
||||||
@ -400,6 +449,22 @@ typedef enum
|
|||||||
[self _layoutRecipientLabel];
|
[self _layoutRecipientLabel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setHasDotPicker:(bool)hasDotPicker {
|
||||||
|
_hasDotPicker = hasDotPicker;
|
||||||
|
_dotHandle.hidden = !hasDotPicker;
|
||||||
|
_scrubberHandle.hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDotVideoView:(UIView *)dotVideoView {
|
||||||
|
_dotVideoView = dotVideoView;
|
||||||
|
_dotVideoView.frame = CGRectInset(_dotHandle.bounds, 2.0, 2.0);
|
||||||
|
[_dotHandle insertSubview:dotVideoView belowSubview:_dotFrameView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDotImage:(UIImage *)dotImage {
|
||||||
|
_dotImageView.image = dotImage;
|
||||||
|
}
|
||||||
|
|
||||||
- (bool)zoomAvailable
|
- (bool)zoomAvailable
|
||||||
{
|
{
|
||||||
if (_disableZoom || _zoomedIn || _preparingToZoomIn || _summaryTimestamps.count == 0)
|
if (_disableZoom || _zoomedIn || _preparingToZoomIn || _summaryTimestamps.count == 0)
|
||||||
@ -886,13 +951,18 @@ typedef enum
|
|||||||
CGPoint point = [self _scrubberPositionForPosition:_value duration:_duration zoomedIn:zoomedIn];
|
CGPoint point = [self _scrubberPositionForPosition:_value duration:_duration zoomedIn:zoomedIn];
|
||||||
CGRect frame = CGRectMake(CGFloor(point.x) - _scrubberHandle.frame.size.width / 2, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
CGRect frame = CGRectMake(CGFloor(point.x) - _scrubberHandle.frame.size.width / 2, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
||||||
|
|
||||||
|
CGPoint dotPoint = [self _dotPositionForPosition:_value duration:_duration];
|
||||||
|
CGRect dotFrame = CGRectMake(CGFloor(dotPoint.x) - _dotHandle.frame.size.width / 2, _dotHandle.frame.origin.y, _dotHandle.frame.size.width, _dotHandle.frame.size.height);
|
||||||
|
|
||||||
if (_trimStartValue > DBL_EPSILON && fabs(_value - _trimStartValue) < 0.01)
|
if (_trimStartValue > DBL_EPSILON && fabs(_value - _trimStartValue) < 0.01)
|
||||||
{
|
{
|
||||||
frame = CGRectMake(_trimView.frame.origin.x + [self _scrubbingRectZoomedIn:zoomedIn].origin.x, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
frame = CGRectMake(_trimView.frame.origin.x + [self _scrubbingRectZoomedIn:zoomedIn].origin.x, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
||||||
|
dotFrame = CGRectMake(_trimView.frame.origin.x + [self _scrubbingRectZoomedIn:false].origin.x, _dotHandle.frame.origin.y, _dotHandle.frame.size.width, _dotHandle.frame.size.height);
|
||||||
}
|
}
|
||||||
else if (fabs(_value - _trimEndValue) < 0.01)
|
else if (fabs(_value - _trimEndValue) < 0.01)
|
||||||
{
|
{
|
||||||
frame = CGRectMake(_trimView.frame.origin.x + _trimView.frame.size.width - [self _scrubbingRectZoomedIn:zoomedIn].origin.x - _scrubberHandle.frame.size.width, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
frame = CGRectMake(_trimView.frame.origin.x + _trimView.frame.size.width - [self _scrubbingRectZoomedIn:zoomedIn].origin.x - _scrubberHandle.frame.size.width, _scrubberHandle.frame.origin.y, _scrubberHandle.frame.size.width, _scrubberHandle.frame.size.height);
|
||||||
|
dotFrame = CGRectMake(_trimView.frame.origin.x + _trimView.frame.size.width - [self _scrubbingRectZoomedIn:false].origin.x - _dotHandle.frame.size.width, _dotHandle.frame.origin.y, _dotHandle.frame.size.width, _dotHandle.frame.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isPlaying)
|
if (_isPlaying)
|
||||||
@ -921,6 +991,8 @@ typedef enum
|
|||||||
[self removeHandleAnimation];
|
[self removeHandleAnimation];
|
||||||
_scrubberHandle.frame = frame;
|
_scrubberHandle.frame = frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_dotHandle.frame = dotFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addHandleAnimationFromFrame:(CGRect)fromFrame toFrame:(CGRect)toFrame duration:(NSTimeInterval)duration
|
- (void)addHandleAnimationFromFrame:(CGRect)fromFrame toFrame:(CGRect)toFrame duration:(NSTimeInterval)duration
|
||||||
@ -1030,6 +1102,8 @@ typedef enum
|
|||||||
CGPoint translation = [gestureRecognizer translationInView:self];
|
CGPoint translation = [gestureRecognizer translationInView:self];
|
||||||
[gestureRecognizer setTranslation:CGPointZero inView:self];
|
[gestureRecognizer setTranslation:CGPointZero inView:self];
|
||||||
|
|
||||||
|
UIView *handle = gestureRecognizer.view;
|
||||||
|
|
||||||
switch (gestureRecognizer.state)
|
switch (gestureRecognizer.state)
|
||||||
{
|
{
|
||||||
case UIGestureRecognizerStateBegan:
|
case UIGestureRecognizerStateBegan:
|
||||||
@ -1059,23 +1133,23 @@ typedef enum
|
|||||||
|
|
||||||
CGRect scrubbingRect = [self _scrubbingRect];
|
CGRect scrubbingRect = [self _scrubbingRect];
|
||||||
CGRect normalScrubbingRect = [self _scrubbingRectZoomedIn:false];
|
CGRect normalScrubbingRect = [self _scrubbingRectZoomedIn:false];
|
||||||
CGFloat minPosition = scrubbingRect.origin.x + _scrubberHandle.frame.size.width / 2;
|
CGFloat minPosition = scrubbingRect.origin.x + handle.frame.size.width / 2;
|
||||||
CGFloat maxPosition = scrubbingRect.origin.x + scrubbingRect.size.width - _scrubberHandle.frame.size.width / 2;
|
CGFloat maxPosition = scrubbingRect.origin.x + scrubbingRect.size.width - handle.frame.size.width / 2;
|
||||||
if (self.allowsTrimming)
|
if (self.allowsTrimming)
|
||||||
{
|
{
|
||||||
minPosition = MAX(minPosition, _trimView.frame.origin.x + normalScrubbingRect.origin.x + _scrubberHandle.frame.size.width / 2);
|
minPosition = MAX(minPosition, _trimView.frame.origin.x + normalScrubbingRect.origin.x + handle.frame.size.width / 2);
|
||||||
maxPosition = MIN(maxPosition, CGRectGetMaxX(_trimView.frame) - normalScrubbingRect.origin.x - _scrubberHandle.frame.size.width / 2);
|
maxPosition = MIN(maxPosition, CGRectGetMaxX(_trimView.frame) - normalScrubbingRect.origin.x - handle.frame.size.width / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
_scrubberHandle.center = CGPointMake(MIN(MAX(_scrubberHandle.center.x + translation.x, minPosition), maxPosition), _scrubberHandle.center.y);
|
handle.center = CGPointMake(MIN(MAX(handle.center.x + translation.x, minPosition), maxPosition), handle.center.y);
|
||||||
|
|
||||||
NSTimeInterval position = [self _positionForScrubberPosition:_scrubberHandle.center duration:_duration];
|
NSTimeInterval position = [self _positionForScrubberPosition:handle.center duration:_duration];
|
||||||
|
|
||||||
if (self.allowsTrimming)
|
if (self.allowsTrimming)
|
||||||
{
|
{
|
||||||
if (ABS(_scrubberHandle.center.x - minPosition) < FLT_EPSILON)
|
if (ABS(handle.center.x - minPosition) < FLT_EPSILON)
|
||||||
position = _trimStartValue;
|
position = _trimStartValue;
|
||||||
else if (ABS(_scrubberHandle.center.x - maxPosition) < FLT_EPSILON)
|
else if (ABS(handle.center.x - maxPosition) < FLT_EPSILON)
|
||||||
position = _trimEndValue;
|
position = _trimEndValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,8 +1179,6 @@ typedef enum
|
|||||||
|
|
||||||
_scrubbing = false;
|
_scrubbing = false;
|
||||||
|
|
||||||
[self setDotValue:_value];
|
|
||||||
|
|
||||||
id<TGMediaPickerGalleryVideoScrubberDelegate> delegate = self.delegate;
|
id<TGMediaPickerGalleryVideoScrubberDelegate> delegate = self.delegate;
|
||||||
if ([delegate respondsToSelector:@selector(videoScrubberDidEndScrubbing:)])
|
if ([delegate respondsToSelector:@selector(videoScrubberDidEndScrubbing:)])
|
||||||
[delegate videoScrubberDidEndScrubbing:self];
|
[delegate videoScrubberDidEndScrubbing:self];
|
||||||
@ -1145,6 +1217,27 @@ typedef enum
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setDotHandleHidden:(bool)hidden animated:(bool)animated
|
||||||
|
{
|
||||||
|
if (animated)
|
||||||
|
{
|
||||||
|
_dotHandle.hidden = false;
|
||||||
|
[UIView animateWithDuration:0.25f animations:^
|
||||||
|
{
|
||||||
|
_dotHandle.alpha = hidden ? 0.0f : 1.0f;
|
||||||
|
} completion:^(BOOL finished)
|
||||||
|
{
|
||||||
|
if (finished)
|
||||||
|
_dotHandle.hidden = hidden;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dotHandle.hidden = hidden;
|
||||||
|
_dotHandle.alpha = hidden ? 0.0f : 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (CGPoint)_scrubberPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration
|
- (CGPoint)_scrubberPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration
|
||||||
{
|
{
|
||||||
return [self _scrubberPositionForPosition:position duration:duration zoomedIn:_zoomedIn];
|
return [self _scrubberPositionForPosition:position duration:duration zoomedIn:_zoomedIn];
|
||||||
@ -1202,25 +1295,17 @@ typedef enum
|
|||||||
|
|
||||||
#pragma mark - Dot
|
#pragma mark - Dot
|
||||||
|
|
||||||
- (void)setDotValue:(NSTimeInterval)dotValue
|
- (CGPoint)_dotPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration
|
||||||
{
|
{
|
||||||
_dotValue = dotValue;
|
CGRect scrubbingRect = [self _scrubbingRectZoomedIn:false];
|
||||||
|
|
||||||
if (dotValue > FLT_EPSILON) {
|
if (duration < FLT_EPSILON)
|
||||||
_dotView.hidden = false;
|
{
|
||||||
|
position = 0.0;
|
||||||
CGPoint point = [self _scrubberPositionForPosition:dotValue duration:_duration zoomedIn:false];
|
duration = 1.0;
|
||||||
_dotView.frame = CGRectMake(_wrapperView.frame.origin.x + point.x - _dotView.frame.size.width / 2.0, 8.0f, _dotView.frame.size.width, _dotView.frame.size.height);
|
|
||||||
|
|
||||||
_dotView.alpha = 0.0f;
|
|
||||||
_dotView.transform = CGAffineTransformMakeScale(0.25, 0.25);
|
|
||||||
[UIView animateWithDuration:0.2 animations:^{
|
|
||||||
_dotView.alpha = 1.0;
|
|
||||||
_dotView.transform = CGAffineTransformIdentity;
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
_dotView.hidden = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return CGPointMake(_dotHandle.frame.size.width / 2 + scrubbingRect.origin.x + (CGFloat)(position / duration) * (scrubbingRect.size.width - _dotHandle.frame.size.width), CGRectGetMidY([self _scrubbingRect]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Trimming
|
#pragma mark - Trimming
|
||||||
|
|||||||
@ -125,7 +125,7 @@
|
|||||||
|
|
||||||
CGSize dimensions = [avAsset tracksWithMediaType:AVMediaTypeVideo].firstObject.naturalSize;
|
CGSize dimensions = [avAsset tracksWithMediaType:AVMediaTypeVideo].firstObject.naturalSize;
|
||||||
TGMediaVideoConversionPreset preset = adjustments.sendAsGif ? TGMediaVideoConversionPresetAnimation : [self presetFromAdjustments:adjustments];
|
TGMediaVideoConversionPreset preset = adjustments.sendAsGif ? TGMediaVideoConversionPresetAnimation : [self presetFromAdjustments:adjustments];
|
||||||
if (!CGSizeEqualToSize(dimensions, CGSizeZero) && preset != TGMediaVideoConversionPresetAnimation && preset != TGMediaVideoConversionPresetVideoMessage)
|
if (!CGSizeEqualToSize(dimensions, CGSizeZero) && preset != TGMediaVideoConversionPresetAnimation && preset != TGMediaVideoConversionPresetVideoMessage && preset != TGMediaVideoConversionPresetProfile)
|
||||||
{
|
{
|
||||||
TGMediaVideoConversionPreset bestPreset = [self bestAvailablePresetForDimensions:dimensions];
|
TGMediaVideoConversionPreset bestPreset = [self bestAvailablePresetForDimensions:dimensions];
|
||||||
if (preset > bestPreset)
|
if (preset > bestPreset)
|
||||||
@ -344,8 +344,6 @@
|
|||||||
if (TGOrientationIsSideward(adjustments.cropOrientation, NULL))
|
if (TGOrientationIsSideward(adjustments.cropOrientation, NULL))
|
||||||
outputDimensions = CGSizeMake(outputDimensions.height, outputDimensions.width);
|
outputDimensions = CGSizeMake(outputDimensions.height, outputDimensions.width);
|
||||||
|
|
||||||
CMTimeRange instructionTimeRange = CMTimeRangeMake(kCMTimeZero, timeRange.duration);
|
|
||||||
|
|
||||||
AVMutableCompositionTrack *compositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
|
AVMutableCompositionTrack *compositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||||
if (adjustments.videoStartValue > 0.0 && adjustments.videoStartValue > adjustments.trimStartValue) {
|
if (adjustments.videoStartValue > 0.0 && adjustments.videoStartValue > adjustments.trimStartValue) {
|
||||||
NSTimeInterval trimEndValue = adjustments.trimEndValue > adjustments.trimStartValue ? adjustments.trimEndValue : CMTimeGetSeconds(videoTrack.timeRange.duration);
|
NSTimeInterval trimEndValue = adjustments.trimEndValue > adjustments.trimStartValue ? adjustments.trimEndValue : CMTimeGetSeconds(videoTrack.timeRange.duration);
|
||||||
@ -1340,7 +1338,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||||||
return 300;
|
return 300;
|
||||||
|
|
||||||
case TGMediaVideoConversionPresetProfile:
|
case TGMediaVideoConversionPresetProfile:
|
||||||
return 1000;
|
return 1800;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 900;
|
return 900;
|
||||||
|
|||||||
@ -172,8 +172,11 @@
|
|||||||
if ([_manager managesWindow]) {
|
if ([_manager managesWindow]) {
|
||||||
_contentController = contentController;
|
_contentController = contentController;
|
||||||
__weak TGOverlayControllerWindow *weakSelf = self;
|
__weak TGOverlayControllerWindow *weakSelf = self;
|
||||||
|
__weak TGViewController *weakParentController = parentController;
|
||||||
contentController.customDismissBlock = ^{
|
contentController.customDismissBlock = ^{
|
||||||
__strong TGOverlayControllerWindow *strongSelf = weakSelf;
|
__strong TGOverlayControllerWindow *strongSelf = weakSelf;
|
||||||
|
__strong TGViewController *strongParentController = weakParentController;
|
||||||
|
[strongParentController.associatedWindowStack removeObject:strongSelf];
|
||||||
[manager setHidden:true window:strongSelf];
|
[manager setHidden:true window:strongSelf];
|
||||||
};
|
};
|
||||||
[_manager bindController:contentController];
|
[_manager bindController:contentController];
|
||||||
|
|||||||
@ -277,6 +277,8 @@ const CGFloat TGPhotoAvatarCropButtonsWrapperSize = 61.0f;
|
|||||||
{
|
{
|
||||||
[_cropView hideImageForCustomTransition];
|
[_cropView hideImageForCustomTransition];
|
||||||
[_cropView animateTransitionOutSwitching:false];
|
[_cropView animateTransitionOutSwitching:false];
|
||||||
|
[_cropView invalidateVideoView];
|
||||||
|
|
||||||
[UIView animateWithDuration:0.3f animations:^
|
[UIView animateWithDuration:0.3f animations:^
|
||||||
{
|
{
|
||||||
_buttonsWrapperView.alpha = 0.0f;
|
_buttonsWrapperView.alpha = 0.0f;
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#import "TGPhotoEditorSparseView.h"
|
#import "TGPhotoEditorSparseView.h"
|
||||||
|
|
||||||
#import "TGMediaPickerGalleryVideoScrubber.h"
|
#import "TGMediaPickerGalleryVideoScrubber.h"
|
||||||
|
#import "TGModernGalleryVideoView.h"
|
||||||
|
|
||||||
const CGFloat TGPhotoAvatarPreviewPanelSize = 96.0f;
|
const CGFloat TGPhotoAvatarPreviewPanelSize = 96.0f;
|
||||||
const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanelSize + 40.0f;
|
const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanelSize + 40.0f;
|
||||||
@ -36,6 +37,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
CGFloat _currentDiameter;
|
CGFloat _currentDiameter;
|
||||||
|
|
||||||
TGMediaPickerGalleryVideoScrubber *_scrubberView;
|
TGMediaPickerGalleryVideoScrubber *_scrubberView;
|
||||||
|
TGModernGalleryVideoView *_dotVideoView;
|
||||||
UILabel *_coverLabel;
|
UILabel *_coverLabel;
|
||||||
bool _wasPlayingBeforeScrubbing;
|
bool _wasPlayingBeforeScrubbing;
|
||||||
bool _requestingThumbnails;
|
bool _requestingThumbnails;
|
||||||
@ -139,11 +141,13 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
{
|
{
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
_scrubberView.allowsTrimming = true;
|
_scrubberView.allowsTrimming = self.item.originalDuration >= TGVideoEditMinimumTrimmableDuration;
|
||||||
|
_scrubberView.hasDotPicker = true;
|
||||||
_scrubberView.disableZoom = true;
|
_scrubberView.disableZoom = true;
|
||||||
_scrubberView.disableTimeDisplay = true;
|
_scrubberView.disableTimeDisplay = true;
|
||||||
_scrubberView.trimStartValue = 0.0;
|
_scrubberView.trimStartValue = 0.0;
|
||||||
_scrubberView.trimEndValue = self.item.originalDuration;
|
_scrubberView.trimEndValue = MIN(10.0, self.item.originalDuration);
|
||||||
|
_scrubberView.maximumLength = 10.0;
|
||||||
[_scrubberView reloadData];
|
[_scrubberView reloadData];
|
||||||
[_scrubberView resetToStart];
|
[_scrubberView resetToStart];
|
||||||
}
|
}
|
||||||
@ -169,11 +173,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
_landscapeToolsWrapperView.alpha = 1.0f;
|
_landscapeToolsWrapperView.alpha = 1.0f;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
switch (self.effectiveOrientation)
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
switch (orientation)
|
|
||||||
{
|
{
|
||||||
case UIInterfaceOrientationLandscapeLeft:
|
case UIInterfaceOrientationLandscapeLeft:
|
||||||
{
|
{
|
||||||
@ -217,11 +217,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
|
|
||||||
[_videoAreaView.superview bringSubviewToFront:_videoAreaView];
|
[_videoAreaView.superview bringSubviewToFront:_videoAreaView];
|
||||||
|
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
switch (self.effectiveOrientation)
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
switch (orientation)
|
|
||||||
{
|
{
|
||||||
case UIInterfaceOrientationLandscapeLeft:
|
case UIInterfaceOrientationLandscapeLeft:
|
||||||
{
|
{
|
||||||
@ -383,11 +379,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
|
|
||||||
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
||||||
{
|
{
|
||||||
bool hasOnScreenNavigation = false;
|
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
||||||
CGRect sourceFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
CGRect sourceFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
|
|
||||||
@ -397,16 +389,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||||
{
|
{
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:0 hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
|
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||||
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
|
|
||||||
@ -441,11 +424,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
|
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
|
||||||
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
|
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
||||||
screenEdges.top += safeAreaInset.top;
|
screenEdges.top += safeAreaInset.top;
|
||||||
screenEdges.left += safeAreaInset.left;
|
screenEdges.left += safeAreaInset.left;
|
||||||
@ -517,10 +496,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
|
|
||||||
- (void)updatePreviewView
|
- (void)updatePreviewView
|
||||||
{
|
{
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
|
||||||
if ([self inFormSheet] || TGIsPad())
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
|
|
||||||
PGPhotoEditor *photoEditor = self.photoEditor;
|
PGPhotoEditor *photoEditor = self.photoEditor;
|
||||||
@ -529,11 +504,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
if (_dismissing || previewView.superview != self.view)
|
if (_dismissing || previewView.superview != self.view)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:0 hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:0 hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size);
|
||||||
previewView.frame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
previewView.frame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
|
|
||||||
@ -588,12 +559,12 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
|
|
||||||
- (TGPhotoEditorTab)availableTabs
|
- (TGPhotoEditorTab)availableTabs
|
||||||
{
|
{
|
||||||
return TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
|
return TGPhotoEditorCropTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (TGPhotoEditorTab)activeTab
|
- (TGPhotoEditorTab)activeTab
|
||||||
{
|
{
|
||||||
return TGPhotoEditorCropTab;
|
return TGPhotoEditorNoneTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (TGPhotoEditorTab)highlightedTabs
|
- (TGPhotoEditorTab)highlightedTabs
|
||||||
@ -681,7 +652,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
_wasPlayingBeforeScrubbing = true;
|
_wasPlayingBeforeScrubbing = true;
|
||||||
self.controlVideoPlayback(false);
|
self.controlVideoPlayback(false);
|
||||||
|
|
||||||
_scrubberView.dotValue = 0.0;
|
_dotVideoView.hidden = false;
|
||||||
|
|
||||||
_coverLabel.alpha = 1.0f;
|
_coverLabel.alpha = 1.0f;
|
||||||
|
|
||||||
@ -694,6 +665,19 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
|
|
||||||
- (void)videoScrubberDidEndScrubbing:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber
|
- (void)videoScrubberDidEndScrubbing:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber
|
||||||
{
|
{
|
||||||
|
AVPlayer *player = ((TGPhotoEditorController *)self.parentViewController).player;
|
||||||
|
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:player.currentItem.asset];
|
||||||
|
generator.appliesPreferredTrackTransform = true;
|
||||||
|
generator.maximumSize = CGSizeMake(128.0f, 128.0f);
|
||||||
|
generator.requestedTimeToleranceAfter = kCMTimeZero;
|
||||||
|
generator.requestedTimeToleranceBefore = kCMTimeZero;
|
||||||
|
CGImageRef imageRef = [generator copyCGImageAtTime:player.currentItem.currentTime actualTime:NULL error:NULL];
|
||||||
|
UIImage *thumbnailImage = [[UIImage alloc] initWithCGImage:imageRef];
|
||||||
|
CGImageRelease(imageRef);
|
||||||
|
|
||||||
|
[_scrubberView setDotImage:thumbnailImage];
|
||||||
|
_dotVideoView.hidden = true;
|
||||||
|
|
||||||
[UIView animateWithDuration:0.12 animations:^{
|
[UIView animateWithDuration:0.12 animations:^{
|
||||||
_flashView.alpha = 1.0f;
|
_flashView.alpha = 1.0f;
|
||||||
} completion:^(BOOL finished) {
|
} completion:^(BOOL finished) {
|
||||||
@ -791,18 +775,30 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
|
|
||||||
id<TGMediaEditAdjustments> adjustments = [self.photoEditor exportAdjustments];
|
id<TGMediaEditAdjustments> adjustments = [self.photoEditor exportAdjustments];
|
||||||
|
|
||||||
|
NSArray *cachedThumbnails = ((TGPhotoEditorController *)self.parentViewController).cachedVideoThumbnails;
|
||||||
|
|
||||||
SSignal *thumbnailsSignal = nil;
|
SSignal *thumbnailsSignal = nil;
|
||||||
if ([self.item isKindOfClass:[TGMediaAsset class]])
|
if (cachedThumbnails.count > 0) {
|
||||||
|
thumbnailsSignal = [SSignal single:cachedThumbnails];
|
||||||
|
} else if ([self.item isKindOfClass:[TGMediaAsset class]]) {
|
||||||
thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAsset:(TGMediaAsset *)self.item size:size timestamps:timestamps];
|
thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAsset:(TGMediaAsset *)self.item size:size timestamps:timestamps];
|
||||||
else if ([self.item isKindOfClass:[TGCameraCapturedVideo class]])
|
} else if ([self.item isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||||
thumbnailsSignal = [((TGCameraCapturedVideo *)self.item).avAsset mapToSignal:^SSignal *(AVAsset *avAsset) {
|
thumbnailsSignal = [((TGCameraCapturedVideo *)self.item).avAsset mapToSignal:^SSignal *(AVAsset *avAsset) {
|
||||||
return [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps];
|
return [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps];
|
||||||
}];
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
_requestingThumbnails = true;
|
_requestingThumbnails = true;
|
||||||
|
|
||||||
__weak TGPhotoAvatarPreviewController *weakSelf = self;
|
__weak TGPhotoAvatarPreviewController *weakSelf = self;
|
||||||
[_thumbnailsDisposable setDisposable:[[[thumbnailsSignal map:^NSArray *(NSArray *images) {
|
[_thumbnailsDisposable setDisposable:[[[[thumbnailsSignal onNext:^(NSArray *images) {
|
||||||
|
__strong TGPhotoAvatarPreviewController *strongSelf = weakSelf;
|
||||||
|
if (strongSelf == nil)
|
||||||
|
return;
|
||||||
|
TGDispatchOnMainThread(^{
|
||||||
|
((TGPhotoEditorController *)strongSelf.parentViewController).cachedVideoThumbnails = images;
|
||||||
|
});
|
||||||
|
}] map:^NSArray *(NSArray *images) {
|
||||||
if (adjustments.toolsApplied) {
|
if (adjustments.toolsApplied) {
|
||||||
NSMutableArray *editedImages = [[NSMutableArray alloc] init];
|
NSMutableArray *editedImages = [[NSMutableArray alloc] init];
|
||||||
PGPhotoEditor *editor = [[PGPhotoEditor alloc] initWithOriginalSize:adjustments.originalSize adjustments:adjustments forVideo:false enableStickers:true];
|
PGPhotoEditor *editor = [[PGPhotoEditor alloc] initWithOriginalSize:adjustments.originalSize adjustments:adjustments forVideo:false enableStickers:true];
|
||||||
@ -868,16 +864,22 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
|||||||
|
|
||||||
- (void)setScrubberPosition:(NSTimeInterval)position reset:(bool)reset
|
- (void)setScrubberPosition:(NSTimeInterval)position reset:(bool)reset
|
||||||
{
|
{
|
||||||
[_scrubberView setValue:_scrubberView.trimStartValue resetPosition:reset];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setScrubberPlaying:(bool)value
|
- (void)setScrubberPlaying:(bool)value
|
||||||
{
|
{
|
||||||
[_scrubberView setIsPlaying:value];
|
if (_dotVideoView == nil) {
|
||||||
|
AVPlayer *player = ((TGPhotoEditorController *)self.parentViewController).player;
|
||||||
|
_dotVideoView = [[TGModernGalleryVideoView alloc] initWithFrame:CGRectMake(0.0, 0.0, 27.0, 44.0) player:player];
|
||||||
|
_dotVideoView.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||||
|
_dotVideoView.hidden = true;
|
||||||
|
[_scrubberView setDotVideoView:_dotVideoView];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSTimeInterval)coverPosition {
|
- (NSTimeInterval)coverPosition {
|
||||||
return _scrubberView.dotValue;
|
return _scrubberView.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -37,9 +37,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
CGFloat _autoRotationAngle;
|
CGFloat _autoRotationAngle;
|
||||||
|
|
||||||
UIView *_buttonsWrapperView;
|
UIView *_buttonsWrapperView;
|
||||||
TGModernButton *_rotateButton;
|
|
||||||
TGModernButton *_mirrorButton;
|
|
||||||
TGModernButton *_aspectRatioButton;
|
|
||||||
TGModernButton *_resetButton;
|
TGModernButton *_resetButton;
|
||||||
|
|
||||||
TGPhotoCropView *_cropView;
|
TGPhotoCropView *_cropView;
|
||||||
@ -107,7 +104,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
[self.view addSubview:_wrapperView];
|
[self.view addSubview:_wrapperView];
|
||||||
|
|
||||||
PGPhotoEditor *photoEditor = self.photoEditor;
|
PGPhotoEditor *photoEditor = self.photoEditor;
|
||||||
_cropView = [[TGPhotoCropView alloc] initWithOriginalSize:photoEditor.originalSize hasArbitraryRotation:true];
|
_cropView = [[TGPhotoCropView alloc] initWithOriginalSize:photoEditor.originalSize hasArbitraryRotation:!_forVideo];
|
||||||
[_cropView setCropRect:photoEditor.cropRect];
|
[_cropView setCropRect:photoEditor.cropRect];
|
||||||
[_cropView setCropOrientation:photoEditor.cropOrientation];
|
[_cropView setCropOrientation:photoEditor.cropOrientation];
|
||||||
[_cropView setRotation:photoEditor.cropRotation];
|
[_cropView setRotation:photoEditor.cropRotation];
|
||||||
@ -153,31 +150,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
_buttonsWrapperView = [[UIView alloc] initWithFrame:CGRectZero];
|
_buttonsWrapperView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[_wrapperView addSubview:_buttonsWrapperView];
|
[_wrapperView addSubview:_buttonsWrapperView];
|
||||||
|
|
||||||
_rotateButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 36, 36)];
|
|
||||||
_rotateButton.exclusiveTouch = true;
|
|
||||||
_rotateButton.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10);
|
|
||||||
[_rotateButton addTarget:self action:@selector(rotate) forControlEvents:UIControlEventTouchUpInside];
|
|
||||||
[_rotateButton setImage:TGComponentsImageNamed(@"PhotoEditorRotateIcon") forState:UIControlStateNormal];
|
|
||||||
//[_buttonsWrapperView addSubview:_rotateButton];
|
|
||||||
|
|
||||||
_mirrorButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 36, 36)];
|
|
||||||
_mirrorButton.exclusiveTouch = true;
|
|
||||||
_mirrorButton.imageEdgeInsets = UIEdgeInsetsMake(4.0f, 0.0f, 0.0f, 0.0f);
|
|
||||||
_mirrorButton.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10);
|
|
||||||
[_mirrorButton addTarget:self action:@selector(mirror) forControlEvents:UIControlEventTouchUpInside];
|
|
||||||
[_mirrorButton setImage:TGComponentsImageNamed(@"PhotoEditorMirrorIcon") forState:UIControlStateNormal];
|
|
||||||
//[_buttonsWrapperView addSubview:_mirrorButton];
|
|
||||||
|
|
||||||
_aspectRatioButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 36, 36)];
|
|
||||||
_aspectRatioButton.exclusiveTouch = true;
|
|
||||||
_aspectRatioButton.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10);
|
|
||||||
[_aspectRatioButton addTarget:self action:@selector(aspectRatioButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
|
||||||
UIImage *aspectRatioHighlightedImage = TGTintedImage(TGComponentsImageNamed(@"PhotoEditorAspectRatioIcon"), [TGPhotoEditorInterfaceAssets accentColor]);
|
|
||||||
[_aspectRatioButton setImage:TGComponentsImageNamed(@"PhotoEditorAspectRatioIcon") forState:UIControlStateNormal];
|
|
||||||
[_aspectRatioButton setImage:aspectRatioHighlightedImage forState:UIControlStateSelected];
|
|
||||||
[_aspectRatioButton setImage:aspectRatioHighlightedImage forState:UIControlStateSelected | UIControlStateHighlighted];
|
|
||||||
//[_buttonsWrapperView addSubview:_aspectRatioButton];
|
|
||||||
|
|
||||||
NSString *resetButtonTitle = TGLocalized(@"PhotoEditor.CropReset");
|
NSString *resetButtonTitle = TGLocalized(@"PhotoEditor.CropReset");
|
||||||
_resetButton = [[TGModernButton alloc] init];
|
_resetButton = [[TGModernButton alloc] init];
|
||||||
_resetButton.exclusiveTouch = true;
|
_resetButton.exclusiveTouch = true;
|
||||||
@ -190,14 +162,10 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
_resetButton.frame = CGRectMake(0, 0, _resetButton.frame.size.width, 24);
|
_resetButton.frame = CGRectMake(0, 0, _resetButton.frame.size.width, 24);
|
||||||
[_buttonsWrapperView addSubview:_resetButton];
|
[_buttonsWrapperView addSubview:_resetButton];
|
||||||
|
|
||||||
if ([resetButtonTitle respondsToSelector:@selector(sizeWithAttributes:)])
|
|
||||||
_resetButtonWidth = CGCeil([resetButtonTitle sizeWithAttributes:@{ NSFontAttributeName:TGSystemFontOfSize(13) }].width);
|
_resetButtonWidth = CGCeil([resetButtonTitle sizeWithAttributes:@{ NSFontAttributeName:TGSystemFontOfSize(13) }].width);
|
||||||
else
|
|
||||||
_resetButtonWidth = CGCeil([resetButtonTitle sizeWithFont:TGSystemFontOfSize(13)].width);
|
|
||||||
|
|
||||||
if (photoEditor.cropLockedAspectRatio > FLT_EPSILON)
|
if (photoEditor.cropLockedAspectRatio > FLT_EPSILON)
|
||||||
{
|
{
|
||||||
_aspectRatioButton.selected = true;
|
|
||||||
[_cropView setLockedAspectRatio:photoEditor.cropLockedAspectRatio performResize:false animated:false];
|
[_cropView setLockedAspectRatio:photoEditor.cropLockedAspectRatio performResize:false animated:false];
|
||||||
}
|
}
|
||||||
else if ([photoEditor hasDefaultCropping] && ABS(_autoRotationAngle) > FLT_EPSILON)
|
else if ([photoEditor hasDefaultCropping] && ABS(_autoRotationAngle) > FLT_EPSILON)
|
||||||
@ -376,16 +344,11 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||||
{
|
{
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
|
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
bool hasOnScreenNavigation = false;
|
||||||
if (iosMajorVersion() >= 11)
|
if (iosMajorVersion() >= 11)
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoCropController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation hasArbitraryRotation:_cropView.hasArbitraryRotation hasOnScreenNavigation:hasOnScreenNavigation];
|
CGRect containerFrame = [TGPhotoCropController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation hasArbitraryRotation:_cropView.hasArbitraryRotation hasOnScreenNavigation:hasOnScreenNavigation];
|
||||||
containerFrame = CGRectInset(containerFrame, TGPhotoCropAreaInsetSize.width, TGPhotoCropAreaInsetSize.height);
|
containerFrame = CGRectInset(containerFrame, TGPhotoCropAreaInsetSize.width, TGPhotoCropAreaInsetSize.height);
|
||||||
|
|
||||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||||
@ -576,7 +539,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
if (_cropView.isAspectRatioLocked)
|
if (_cropView.isAspectRatioLocked)
|
||||||
{
|
{
|
||||||
[_cropView unlockAspectRatio];
|
[_cropView unlockAspectRatio];
|
||||||
_aspectRatioButton.selected = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -677,14 +639,14 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
}]];
|
}]];
|
||||||
|
|
||||||
[controller setItemViews:items];
|
[controller setItemViews:items];
|
||||||
controller.sourceRect = ^CGRect
|
// controller.sourceRect = ^CGRect
|
||||||
{
|
// {
|
||||||
__strong TGPhotoCropController *strongSelf = weakSelf;
|
// __strong TGPhotoCropController *strongSelf = weakSelf;
|
||||||
if (strongSelf != nil)
|
// if (strongSelf != nil)
|
||||||
return [strongSelf.view convertRect:strongSelf->_aspectRatioButton.frame fromView:strongSelf->_aspectRatioButton.superview];
|
// return [strongSelf.view convertRect:strongSelf->_aspectRatioButton.frame fromView:strongSelf->_aspectRatioButton.superview];
|
||||||
|
//
|
||||||
return CGRectZero;
|
// return CGRectZero;
|
||||||
};
|
// };
|
||||||
[controller presentInViewController:self.parentViewController sourceView:self.view animated:true];
|
[controller presentInViewController:self.parentViewController sourceView:self.view animated:true];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,8 +668,6 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_aspectRatioButton.selected = false;
|
|
||||||
|
|
||||||
[_cropView resetAnimated:true];
|
[_cropView resetAnimated:true];
|
||||||
|
|
||||||
if (hasAutorotationAngle)
|
if (hasAutorotationAngle)
|
||||||
@ -796,8 +756,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
|
|
||||||
- (void)updateLayout:(UIInterfaceOrientation)orientation
|
- (void)updateLayout:(UIInterfaceOrientation)orientation
|
||||||
{
|
{
|
||||||
if ([self inFormSheet] || [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
orientation = [self effectiveOrientation:orientation];
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
|
|
||||||
@ -823,18 +782,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
{
|
{
|
||||||
case UIInterfaceOrientationLandscapeLeft:
|
case UIInterfaceOrientationLandscapeLeft:
|
||||||
{
|
{
|
||||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.left + self.toolbarLandscapeSize,
|
_buttonsWrapperView.frame = CGRectMake(screenEdges.left + self.toolbarLandscapeSize, screenEdges.top, TGPhotoCropButtonsWrapperSize, referenceSize.height);
|
||||||
screenEdges.top,
|
|
||||||
TGPhotoCropButtonsWrapperSize,
|
|
||||||
referenceSize.height);
|
|
||||||
|
|
||||||
_rotateButton.frame = CGRectMake(25, 10, _rotateButton.frame.size.width, _rotateButton.frame.size.height);
|
|
||||||
_mirrorButton.frame = CGRectMake(25, 60, _mirrorButton.frame.size.width, _mirrorButton.frame.size.height);
|
|
||||||
|
|
||||||
_aspectRatioButton.frame = CGRectMake(25,
|
|
||||||
_buttonsWrapperView.frame.size.height - _aspectRatioButton.frame.size.height - 10,
|
|
||||||
_aspectRatioButton.frame.size.width,
|
|
||||||
_aspectRatioButton.frame.size.height);
|
|
||||||
|
|
||||||
_resetButton.transform = CGAffineTransformIdentity;
|
_resetButton.transform = CGAffineTransformIdentity;
|
||||||
_resetButton.frame = CGRectMake(0, 0, _resetButtonWidth, 24);
|
_resetButton.frame = CGRectMake(0, 0, _resetButtonWidth, 24);
|
||||||
@ -852,18 +800,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
|
|
||||||
case UIInterfaceOrientationLandscapeRight:
|
case UIInterfaceOrientationLandscapeRight:
|
||||||
{
|
{
|
||||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.right - self.toolbarLandscapeSize - TGPhotoCropButtonsWrapperSize,
|
_buttonsWrapperView.frame = CGRectMake(screenEdges.right - self.toolbarLandscapeSize - TGPhotoCropButtonsWrapperSize, screenEdges.top, TGPhotoCropButtonsWrapperSize, referenceSize.height);
|
||||||
screenEdges.top,
|
|
||||||
TGPhotoCropButtonsWrapperSize,
|
|
||||||
referenceSize.height);
|
|
||||||
|
|
||||||
_rotateButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _rotateButton.frame.size.width - 25, 10, _rotateButton.frame.size.width, _rotateButton.frame.size.height);
|
|
||||||
_mirrorButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _mirrorButton.frame.size.width - 25, 60, _mirrorButton.frame.size.width, _mirrorButton.frame.size.height);
|
|
||||||
|
|
||||||
_aspectRatioButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _aspectRatioButton.frame.size.width - 25,
|
|
||||||
_buttonsWrapperView.frame.size.height - _aspectRatioButton.frame.size.height - 10,
|
|
||||||
_aspectRatioButton.frame.size.width,
|
|
||||||
_aspectRatioButton.frame.size.height);
|
|
||||||
|
|
||||||
_resetButton.transform = CGAffineTransformIdentity;
|
_resetButton.transform = CGAffineTransformIdentity;
|
||||||
_resetButton.frame = CGRectMake(0, 0, _resetButtonWidth, 24);
|
_resetButton.frame = CGRectMake(0, 0, _resetButtonWidth, 24);
|
||||||
@ -881,18 +818,7 @@ NSString * const TGPhotoCropOriginalAspectRatio = @"original";
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
_buttonsWrapperView.frame = CGRectMake(screenEdges.left,
|
_buttonsWrapperView.frame = CGRectMake(screenEdges.left, screenEdges.bottom - TGPhotoEditorToolbarSize - TGPhotoCropButtonsWrapperSize, referenceSize.width, TGPhotoCropButtonsWrapperSize);
|
||||||
screenEdges.bottom - TGPhotoEditorToolbarSize - TGPhotoCropButtonsWrapperSize,
|
|
||||||
referenceSize.width,
|
|
||||||
TGPhotoCropButtonsWrapperSize);
|
|
||||||
|
|
||||||
_rotateButton.frame = CGRectMake(10, _buttonsWrapperView.frame.size.height - _rotateButton.frame.size.height - 25, _rotateButton.frame.size.width, _rotateButton.frame.size.height);
|
|
||||||
_mirrorButton.frame = CGRectMake(60, _buttonsWrapperView.frame.size.height - _mirrorButton.frame.size.height - 25, _mirrorButton.frame.size.width, _mirrorButton.frame.size.height);
|
|
||||||
|
|
||||||
_aspectRatioButton.frame = CGRectMake(_buttonsWrapperView.frame.size.width - _aspectRatioButton.frame.size.width - 10,
|
|
||||||
_buttonsWrapperView.frame.size.height - _aspectRatioButton.frame.size.height - 25,
|
|
||||||
_aspectRatioButton.frame.size.width,
|
|
||||||
_aspectRatioButton.frame.size.height);
|
|
||||||
|
|
||||||
_resetButton.transform = CGAffineTransformIdentity;
|
_resetButton.transform = CGAffineTransformIdentity;
|
||||||
_resetButton.frame = CGRectMake((_buttonsWrapperView.frame.size.width - _resetButton.frame.size.width) / 2, 20, _resetButtonWidth, 24);
|
_resetButton.frame = CGRectMake((_buttonsWrapperView.frame.size.width - _resetButton.frame.size.width) / 2, 20, _resetButtonWidth, 24);
|
||||||
|
|||||||
@ -72,12 +72,12 @@
|
|||||||
UIImage *_thumbnailImage;
|
UIImage *_thumbnailImage;
|
||||||
|
|
||||||
AVPlayerItem *_playerItem;
|
AVPlayerItem *_playerItem;
|
||||||
AVPlayer *_player;
|
|
||||||
SMetaDisposable *_playerItemDisposable;
|
SMetaDisposable *_playerItemDisposable;
|
||||||
id _playerStartedObserver;
|
id _playerStartedObserver;
|
||||||
id _playerReachedEndObserver;
|
id _playerReachedEndObserver;
|
||||||
bool _registeredKeypathObserver;
|
bool _registeredKeypathObserver;
|
||||||
NSTimer *_positionTimer;
|
NSTimer *_positionTimer;
|
||||||
|
bool _scheduledVideoPlayback;
|
||||||
|
|
||||||
id<TGMediaEditAdjustments> _initialAdjustments;
|
id<TGMediaEditAdjustments> _initialAdjustments;
|
||||||
NSString *_caption;
|
NSString *_caption;
|
||||||
@ -260,14 +260,6 @@
|
|||||||
|
|
||||||
|
|
||||||
TGPhotoEditorBackButton backButton = TGPhotoEditorBackButtonCancel;
|
TGPhotoEditorBackButton backButton = TGPhotoEditorBackButtonCancel;
|
||||||
if ([self presentedForAvatarCreation])
|
|
||||||
{
|
|
||||||
if ([self presentedFromCamera])
|
|
||||||
backButton = TGPhotoEditorBackButtonCancel;
|
|
||||||
else
|
|
||||||
backButton = TGPhotoEditorBackButtonCancel;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGPhotoEditorDoneButton doneButton = TGPhotoEditorDoneButtonCheck;
|
TGPhotoEditorDoneButton doneButton = TGPhotoEditorDoneButtonCheck;
|
||||||
_portraitToolbarView = [[TGPhotoToolbarView alloc] initWithBackButton:backButton doneButton:doneButton solidBackground:true];
|
_portraitToolbarView = [[TGPhotoToolbarView alloc] initWithBackButton:backButton doneButton:doneButton solidBackground:true];
|
||||||
[_portraitToolbarView setToolbarTabs:_availableTabs animated:false];
|
[_portraitToolbarView setToolbarTabs:_availableTabs animated:false];
|
||||||
@ -403,8 +395,11 @@
|
|||||||
|
|
||||||
[signal startWithNext:^(id next)
|
[signal startWithNext:^(id next)
|
||||||
{
|
{
|
||||||
|
CGFloat progress = 0.0;
|
||||||
|
bool progressVisible = false;
|
||||||
if ([next isKindOfClass:[UIImage class]]) {
|
if ([next isKindOfClass:[UIImage class]]) {
|
||||||
[_photoEditor setImage:(UIImage *)next forCropRect:_photoEditor.cropRect cropRotation:_photoEditor.cropRotation cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored fullSize:false];
|
[_photoEditor setImage:(UIImage *)next forCropRect:_photoEditor.cropRect cropRotation:_photoEditor.cropRotation cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored fullSize:false];
|
||||||
|
progress = 1.0f;
|
||||||
} else if ([next isKindOfClass:[AVAsset class]]) {
|
} else if ([next isKindOfClass:[AVAsset class]]) {
|
||||||
_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next];
|
_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next];
|
||||||
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
||||||
@ -421,8 +416,21 @@
|
|||||||
[_previewView performTransitionInWithCompletion:^
|
[_previewView performTransitionInWithCompletion:^
|
||||||
{
|
{
|
||||||
}];
|
}];
|
||||||
});
|
|
||||||
|
if (_scheduledVideoPlayback) {
|
||||||
|
_scheduledVideoPlayback = false;
|
||||||
|
[self startVideoPlayback:true];
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
progress = 1.0f;
|
||||||
|
} else if ([next isKindOfClass:[NSNumber class]]) {
|
||||||
|
progress = [next floatValue];
|
||||||
|
progressVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGDispatchOnMainThread(^{
|
||||||
|
[self setProgressVisible:progressVisible value:progress animated:true];
|
||||||
|
});
|
||||||
|
|
||||||
if (_ignoreDefaultPreviewViewTransitionIn)
|
if (_ignoreDefaultPreviewViewTransitionIn)
|
||||||
{
|
{
|
||||||
@ -496,6 +504,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)startVideoPlayback:(bool)reset {
|
- (void)startVideoPlayback:(bool)reset {
|
||||||
|
if (reset && _player == nil) {
|
||||||
|
_scheduledVideoPlayback = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (reset) {
|
if (reset) {
|
||||||
NSTimeInterval startPosition = 0.0f;
|
NSTimeInterval startPosition = 0.0f;
|
||||||
if (_photoEditor.trimStartValue > DBL_EPSILON)
|
if (_photoEditor.trimStartValue > DBL_EPSILON)
|
||||||
@ -973,6 +986,9 @@
|
|||||||
|
|
||||||
_switchingTab = true;
|
_switchingTab = true;
|
||||||
|
|
||||||
|
TGPhotoEditorBackButton backButtonType = TGPhotoEditorBackButtonCancel;
|
||||||
|
TGPhotoEditorDoneButton doneButtonType = TGPhotoEditorDoneButtonCheck;
|
||||||
|
|
||||||
__weak TGPhotoEditorController *weakSelf = self;
|
__weak TGPhotoEditorController *weakSelf = self;
|
||||||
TGPhotoEditorTabController *controller = nil;
|
TGPhotoEditorTabController *controller = nil;
|
||||||
switch (tab)
|
switch (tab)
|
||||||
@ -1358,6 +1374,8 @@
|
|||||||
[strongSelf setVideoEndTime:endTime];
|
[strongSelf setVideoEndTime:endTime];
|
||||||
};
|
};
|
||||||
controller = previewController;
|
controller = previewController;
|
||||||
|
|
||||||
|
doneButtonType = TGPhotoEditorDoneButtonDone;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1365,6 +1383,10 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_intent == TGPhotoEditorControllerAvatarIntent && !isInitialAppearance && tab != TGPhotoEditorPreviewTab) {
|
||||||
|
backButtonType = TGPhotoEditorBackButtonBack;
|
||||||
|
}
|
||||||
|
|
||||||
_currentTabController = controller;
|
_currentTabController = controller;
|
||||||
_currentTabController.item = _item;
|
_currentTabController.item = _item;
|
||||||
_currentTabController.intent = _intent;
|
_currentTabController.intent = _intent;
|
||||||
@ -1382,11 +1404,11 @@
|
|||||||
if (currentController != nil)
|
if (currentController != nil)
|
||||||
[_currentTabController viewWillAppear:true];
|
[_currentTabController viewWillAppear:true];
|
||||||
|
|
||||||
|
_currentTabController.view.frame = _containerView.bounds;
|
||||||
|
|
||||||
if (currentController != nil)
|
if (currentController != nil)
|
||||||
[_currentTabController viewDidAppear:true];
|
[_currentTabController viewDidAppear:true];
|
||||||
|
|
||||||
_currentTabController.view.frame = _containerView.bounds;
|
|
||||||
|
|
||||||
_currentTabController.valuesChanged = ^
|
_currentTabController.valuesChanged = ^
|
||||||
{
|
{
|
||||||
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
||||||
@ -1405,6 +1427,12 @@
|
|||||||
[_portraitToolbarView setToolbarTabs:[_currentTabController availableTabs] animated:true];
|
[_portraitToolbarView setToolbarTabs:[_currentTabController availableTabs] animated:true];
|
||||||
[_landscapeToolbarView setToolbarTabs:[_currentTabController availableTabs] animated:true];
|
[_landscapeToolbarView setToolbarTabs:[_currentTabController availableTabs] animated:true];
|
||||||
|
|
||||||
|
[_portraitToolbarView setBackButtonType:backButtonType];
|
||||||
|
[_landscapeToolbarView setBackButtonType:backButtonType];
|
||||||
|
|
||||||
|
[_portraitToolbarView setDoneButtonType:doneButtonType];
|
||||||
|
[_landscapeToolbarView setDoneButtonType:doneButtonType];
|
||||||
|
|
||||||
[self updateEditorButtons];
|
[self updateEditorButtons];
|
||||||
|
|
||||||
if ([self respondsToSelector:@selector(setNeedsUpdateOfScreenEdgesDeferringSystemGestures)])
|
if ([self respondsToSelector:@selector(setNeedsUpdateOfScreenEdgesDeferringSystemGestures)])
|
||||||
@ -1474,10 +1502,7 @@
|
|||||||
|
|
||||||
- (void)dismissEditor
|
- (void)dismissEditor
|
||||||
{
|
{
|
||||||
if ([_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
|
if ((![_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]] && ![_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]]) && _intent == TGPhotoEditorControllerAvatarIntent) {
|
||||||
[self presentEditorTab:TGPhotoEditorCropTab];
|
|
||||||
return;
|
|
||||||
} else if (![_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]] && _intent == TGPhotoEditorControllerAvatarIntent) {
|
|
||||||
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1570,9 +1595,7 @@
|
|||||||
|
|
||||||
- (void)doneButtonPressed
|
- (void)doneButtonPressed
|
||||||
{
|
{
|
||||||
if ([_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]]) {
|
if (_intent == TGPhotoEditorControllerAvatarIntent && ![_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
|
||||||
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
|
||||||
} else if (_intent == TGPhotoEditorControllerAvatarIntent && ![_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
|
|
||||||
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
[self presentEditorTab:TGPhotoEditorPreviewTab];
|
||||||
} else {
|
} else {
|
||||||
[self applyEditor];
|
[self applyEditor];
|
||||||
@ -1895,7 +1918,7 @@
|
|||||||
|
|
||||||
- (void)dismiss
|
- (void)dismiss
|
||||||
{
|
{
|
||||||
if (self.overlayWindow != nil)
|
if (self.overlayWindow != nil || self.customDismissBlock != nil)
|
||||||
{
|
{
|
||||||
[super dismiss];
|
[super dismiss];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,6 +82,13 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (bool)hasOnScreenNavigation {
|
||||||
|
bool hasOnScreenNavigation = false;
|
||||||
|
if (iosMajorVersion() >= 11)
|
||||||
|
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
||||||
|
return hasOnScreenNavigation;
|
||||||
|
}
|
||||||
|
|
||||||
- (UIInterfaceOrientation)effectiveOrientation {
|
- (UIInterfaceOrientation)effectiveOrientation {
|
||||||
return [self effectiveOrientation:self.interfaceOrientation];
|
return [self effectiveOrientation:self.interfaceOrientation];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1830,16 +1830,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||||
{
|
{
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
|
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
|
|
||||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||||
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
@ -1920,11 +1911,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
|
|
||||||
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
||||||
{
|
{
|
||||||
bool hasOnScreenNavigation = false;
|
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
|
|
||||||
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
||||||
return CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
return CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
@ -1942,15 +1929,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
TGPhotoEditorPreviewView *previewView = self.previewView;
|
TGPhotoEditorPreviewView *previewView = self.previewView;
|
||||||
[previewView prepareForTransitionOut];
|
[previewView prepareForTransitionOut];
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
UIInterfaceOrientation orientation = self.effectiveOrientation;
|
||||||
if (iosMajorVersion() >= 11)
|
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
CGRect referenceFrame = CGRectMake(0, 0, self.photoEditor.rotatedCropSize.width, self.photoEditor.rotatedCropSize.height);
|
CGRect referenceFrame = CGRectMake(0, 0, self.photoEditor.rotatedCropSize.width, self.photoEditor.rotatedCropSize.height);
|
||||||
CGRect rect = CGRectOffset([self transitionOutSourceFrameForReferenceFrame:referenceFrame orientation:orientation], -containerFrame.origin.x, -containerFrame.origin.y);
|
CGRect rect = CGRectOffset([self transitionOutSourceFrameForReferenceFrame:referenceFrame orientation:orientation], -containerFrame.origin.x, -containerFrame.origin.y);
|
||||||
previewView.frame = rect;
|
previewView.frame = rect;
|
||||||
@ -2183,18 +2163,14 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
CGFloat panelToolbarPortraitSize = TGPhotoPaintBottomPanelSize + TGPhotoEditorToolbarSize;
|
CGFloat panelToolbarPortraitSize = TGPhotoPaintBottomPanelSize + TGPhotoEditorToolbarSize;
|
||||||
CGFloat panelToolbarLandscapeSize = TGPhotoPaintBottomPanelSize + self.toolbarLandscapeSize;
|
CGFloat panelToolbarLandscapeSize = TGPhotoPaintBottomPanelSize + self.toolbarLandscapeSize;
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
||||||
screenEdges.top += safeAreaInset.top;
|
screenEdges.top += safeAreaInset.top;
|
||||||
screenEdges.left += safeAreaInset.left;
|
screenEdges.left += safeAreaInset.left;
|
||||||
screenEdges.bottom -= safeAreaInset.bottom;
|
screenEdges.bottom -= safeAreaInset.bottom;
|
||||||
screenEdges.right -= safeAreaInset.right;
|
screenEdges.right -= safeAreaInset.right;
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
|
|
||||||
_settingsViewWrapper.frame = self.parentViewController.view.bounds;
|
_settingsViewWrapper.frame = self.parentViewController.view.bounds;
|
||||||
|
|
||||||
@ -2361,18 +2337,10 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
|
|
||||||
- (void)keyboardHeightChangedTo:(CGFloat)height duration:(NSTimeInterval)duration curve:(NSInteger)curve
|
- (void)keyboardHeightChangedTo:(CGFloat)height duration:(NSTimeInterval)duration curve:(NSInteger)curve
|
||||||
{
|
{
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
|
||||||
if ([self inFormSheet] || [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || _context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
CGFloat screenSide = MAX(referenceSize.width, referenceSize.height) + 2 * TGPhotoPaintBottomPanelSize;
|
CGFloat screenSide = MAX(referenceSize.width, referenceSize.height) + 2 * TGPhotoPaintBottomPanelSize;
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
|
|
||||||
CGFloat visibleArea = self.view.frame.size.height - height;
|
CGFloat visibleArea = self.view.frame.size.height - height;
|
||||||
CGFloat yCenter = visibleArea / 2.0f;
|
CGFloat yCenter = visibleArea / 2.0f;
|
||||||
|
|||||||
@ -42,12 +42,34 @@
|
|||||||
_buttonsWrapperView = [[UIView alloc] initWithFrame:_backgroundView.bounds];
|
_buttonsWrapperView = [[UIView alloc] initWithFrame:_backgroundView.bounds];
|
||||||
[_backgroundView addSubview:_buttonsWrapperView];
|
[_backgroundView addSubview:_buttonsWrapperView];
|
||||||
|
|
||||||
_cancelButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 49, 49)];
|
CGSize buttonSize = CGSizeMake(49.0f, 49.0f);
|
||||||
|
_cancelButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, buttonSize.width, buttonSize.height)];
|
||||||
_cancelButton.exclusiveTouch = true;
|
_cancelButton.exclusiveTouch = true;
|
||||||
_cancelButton.adjustsImageWhenHighlighted = false;
|
_cancelButton.adjustsImageWhenHighlighted = false;
|
||||||
|
[self setBackButtonType:backButton];
|
||||||
|
[_cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[_backgroundView addSubview:_cancelButton];
|
||||||
|
|
||||||
|
|
||||||
|
_doneButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, buttonSize.width, buttonSize.height)];
|
||||||
|
_doneButton.exclusiveTouch = true;
|
||||||
|
_doneButton.adjustsImageWhenHighlighted = false;
|
||||||
|
[self setDoneButtonType:doneButton];
|
||||||
|
[_doneButton addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[_backgroundView addSubview:_doneButton];
|
||||||
|
|
||||||
|
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(doneButtonLongPressed:)];
|
||||||
|
_longPressGestureRecognizer.minimumPressDuration = 0.4;
|
||||||
|
[_doneButton addGestureRecognizer:_longPressGestureRecognizer];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBackButtonType:(TGPhotoEditorBackButton)backButtonType {
|
||||||
|
_backButtonType = backButtonType;
|
||||||
|
|
||||||
UIImage *cancelImage = nil;
|
UIImage *cancelImage = nil;
|
||||||
switch (backButton)
|
switch (backButtonType)
|
||||||
{
|
{
|
||||||
case TGPhotoEditorBackButtonCancel:
|
case TGPhotoEditorBackButtonCancel:
|
||||||
cancelImage = TGTintedImage([UIImage imageNamed:@"Editor/Cancel"], [UIColor whiteColor]);
|
cancelImage = TGTintedImage([UIImage imageNamed:@"Editor/Cancel"], [UIColor whiteColor]);
|
||||||
@ -58,17 +80,27 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[_cancelButton setImage:cancelImage forState:UIControlStateNormal];
|
[_cancelButton setImage:cancelImage forState:UIControlStateNormal];
|
||||||
[_cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
}
|
||||||
[_backgroundView addSubview:_cancelButton];
|
|
||||||
|
|
||||||
UIImage *doneImage = nil;
|
- (void)setDoneButtonType:(TGPhotoEditorDoneButton)doneButtonType {
|
||||||
CGSize buttonSize = CGSizeMake(49.0f, 49.0f);
|
_doneButtonType = doneButtonType;
|
||||||
switch (doneButton)
|
|
||||||
|
UIImage *doneImage;
|
||||||
|
switch (doneButtonType)
|
||||||
{
|
{
|
||||||
case TGPhotoEditorDoneButtonCheck:
|
case TGPhotoEditorDoneButtonCheck:
|
||||||
doneImage = TGTintedImage([UIImage imageNamed:@"Editor/Commit"], [UIColor whiteColor]);
|
doneImage = TGTintedImage([UIImage imageNamed:@"Editor/Commit"], [UIColor whiteColor]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TGPhotoEditorDoneButtonDone:
|
||||||
|
{
|
||||||
|
TGMediaAssetsPallete *pallete = nil;
|
||||||
|
if ([[LegacyComponentsGlobals provider] respondsToSelector:@selector(mediaAssetsPallete)])
|
||||||
|
pallete = [[LegacyComponentsGlobals provider] mediaAssetsPallete];
|
||||||
|
|
||||||
|
doneImage = pallete != nil ? pallete.doneIconImage : TGTintedImage([UIImage imageNamed:@"Editor/Commit"], [UIColor whiteColor]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
TGMediaAssetsPallete *pallete = nil;
|
TGMediaAssetsPallete *pallete = nil;
|
||||||
@ -79,20 +111,7 @@
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_doneButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, buttonSize.width, buttonSize.height)];
|
|
||||||
_doneButton.exclusiveTouch = true;
|
|
||||||
_doneButton.adjustsImageWhenHighlighted = false;
|
|
||||||
|
|
||||||
[_doneButton setImage:doneImage forState:UIControlStateNormal];
|
[_doneButton setImage:doneImage forState:UIControlStateNormal];
|
||||||
[_doneButton addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
|
||||||
[_backgroundView addSubview:_doneButton];
|
|
||||||
|
|
||||||
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(doneButtonLongPressed:)];
|
|
||||||
_longPressGestureRecognizer.minimumPressDuration = 0.4;
|
|
||||||
[_doneButton addGestureRecognizer:_longPressGestureRecognizer];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIButton *)doneButton
|
- (UIButton *)doneButton
|
||||||
|
|||||||
@ -30,6 +30,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
{
|
{
|
||||||
NSValue *_contentOffsetAfterRotation;
|
NSValue *_contentOffsetAfterRotation;
|
||||||
bool _appeared;
|
bool _appeared;
|
||||||
|
bool _scheduledTransitionIn;
|
||||||
CGFloat _cellWidth;
|
CGFloat _cellWidth;
|
||||||
|
|
||||||
NSArray *_allTools;
|
NSArray *_allTools;
|
||||||
@ -306,17 +307,17 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
|
|
||||||
- (void)transitionIn
|
- (void)transitionIn
|
||||||
{
|
{
|
||||||
|
if (_portraitToolsWrapperView.frame.size.height < FLT_EPSILON) {
|
||||||
|
_scheduledTransitionIn = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
[UIView animateWithDuration:0.3f animations:^
|
[UIView animateWithDuration:0.3f animations:^
|
||||||
{
|
{
|
||||||
_portraitToolsWrapperView.alpha = 1.0f;
|
_portraitToolsWrapperView.alpha = 1.0f;
|
||||||
_landscapeToolsWrapperView.alpha = 1.0f;
|
_landscapeToolsWrapperView.alpha = 1.0f;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
switch (self.effectiveOrientation)
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
switch (orientation)
|
|
||||||
{
|
{
|
||||||
case UIInterfaceOrientationLandscapeLeft:
|
case UIInterfaceOrientationLandscapeLeft:
|
||||||
{
|
{
|
||||||
@ -350,8 +351,12 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)transitionOutSwitching:(bool)__unused switching completion:(void (^)(void))completion
|
- (void)transitionOutSwitching:(bool)switching completion:(void (^)(void))completion
|
||||||
{
|
{
|
||||||
|
if (switching) {
|
||||||
|
_dismissing = true;
|
||||||
|
}
|
||||||
|
|
||||||
TGPhotoEditorPreviewView *previewView = self.previewView;
|
TGPhotoEditorPreviewView *previewView = self.previewView;
|
||||||
previewView.touchedUp = nil;
|
previewView.touchedUp = nil;
|
||||||
previewView.touchedDown = nil;
|
previewView.touchedDown = nil;
|
||||||
@ -360,11 +365,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
|
|
||||||
[_toolAreaView.superview bringSubviewToFront:_toolAreaView];
|
[_toolAreaView.superview bringSubviewToFront:_toolAreaView];
|
||||||
|
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
switch (self.effectiveOrientation)
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
switch (orientation)
|
|
||||||
{
|
{
|
||||||
case UIInterfaceOrientationLandscapeLeft:
|
case UIInterfaceOrientationLandscapeLeft:
|
||||||
{
|
{
|
||||||
@ -769,17 +770,18 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
|
|
||||||
[self updateLayout:[[LegacyComponentsGlobals provider] applicationStatusBarOrientation]];
|
[self updateLayout:[[LegacyComponentsGlobals provider] applicationStatusBarOrientation]];
|
||||||
|
|
||||||
|
if (_scheduledTransitionIn) {
|
||||||
|
_scheduledTransitionIn = false;
|
||||||
|
[self transitionIn];
|
||||||
|
}
|
||||||
|
|
||||||
if (![self inFormSheet])
|
if (![self inFormSheet])
|
||||||
[self _applyPreparedContentOffset];
|
[self _applyPreparedContentOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation
|
||||||
{
|
{
|
||||||
bool hasOnScreenNavigation = false;
|
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size);
|
||||||
CGRect sourceFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
CGRect sourceFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
|
|
||||||
@ -789,16 +791,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame
|
||||||
{
|
{
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
|
|
||||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size);
|
||||||
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
|
|
||||||
@ -831,11 +824,7 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
|
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
|
||||||
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
|
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
if (iosMajorVersion() >= 11)
|
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
|
||||||
screenEdges.top += safeAreaInset.top;
|
screenEdges.top += safeAreaInset.top;
|
||||||
screenEdges.left += safeAreaInset.left;
|
screenEdges.left += safeAreaInset.left;
|
||||||
@ -946,23 +935,14 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize
|
|||||||
|
|
||||||
- (void)updatePreviewView
|
- (void)updatePreviewView
|
||||||
{
|
{
|
||||||
UIInterfaceOrientation orientation = self.interfaceOrientation;
|
|
||||||
if ([self inFormSheet] || TGIsPad())
|
|
||||||
orientation = UIInterfaceOrientationPortrait;
|
|
||||||
|
|
||||||
CGSize referenceSize = [self referenceViewSize];
|
|
||||||
|
|
||||||
PGPhotoEditor *photoEditor = self.photoEditor;
|
PGPhotoEditor *photoEditor = self.photoEditor;
|
||||||
TGPhotoEditorPreviewView *previewView = self.previewView;
|
TGPhotoEditorPreviewView *previewView = self.previewView;
|
||||||
|
|
||||||
if (_dismissing || previewView.superview != self.view)
|
if (_dismissing || previewView.superview != self.view)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool hasOnScreenNavigation = false;
|
CGSize referenceSize = [self referenceViewSize];
|
||||||
if (iosMajorVersion() >= 11)
|
CGRect containerFrame = _preview ? CGRectMake(0.0f, 0.0f, referenceSize.width, referenceSize.height) : [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation];
|
||||||
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
||||||
|
|
||||||
CGRect containerFrame = _preview ? CGRectMake(0.0f, 0.0f, referenceSize.width, referenceSize.height) : [TGPhotoToolsController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoEditorPanelSize hasOnScreenNavigation:hasOnScreenNavigation];
|
|
||||||
CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size);
|
CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size);
|
||||||
previewView.frame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
previewView.frame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height);
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
#import "TGPhotoPaintStickerEntity.h"
|
#import "TGPhotoPaintStickerEntity.h"
|
||||||
#import "TGPhotoPaintTextEntity.h"
|
#import "TGPhotoPaintTextEntity.h"
|
||||||
|
|
||||||
const NSTimeInterval TGVideoEditMinimumTrimmableDuration = 1.0;
|
const NSTimeInterval TGVideoEditMinimumTrimmableDuration = 1.5;
|
||||||
const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||||
|
|
||||||
@implementation TGVideoEditAdjustments
|
@implementation TGVideoEditAdjustments
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, t
|
|||||||
}
|
}
|
||||||
completion(image)
|
completion(image)
|
||||||
}
|
}
|
||||||
mixin.didFinishWithView = { [weak legacyController] in
|
mixin.didFinishWithView = {
|
||||||
openCurrent?()
|
openCurrent?()
|
||||||
}
|
}
|
||||||
mixin.didDismiss = { [weak legacyController] in
|
mixin.didDismiss = { [weak legacyController] in
|
||||||
|
|||||||
@ -346,7 +346,7 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone
|
|||||||
let navigationBar = presentationTheme.rootController.navigationBar
|
let navigationBar = presentationTheme.rootController.navigationBar
|
||||||
let tabBar = presentationTheme.rootController.tabBar
|
let tabBar = presentationTheme.rootController.tabBar
|
||||||
|
|
||||||
return TGMediaAssetsPallete(dark: presentationTheme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: tabBar.backgroundColor, barSeparatorColor: tabBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationTheme), maybeAccentColor: navigationBar.accentTextColor)
|
return TGMediaAssetsPallete(dark: presentationTheme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: tabBar.backgroundColor, barSeparatorColor: tabBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationTheme), doneIconImage: PresentationResourcesChat.chatInputPanelApplyButtonImage(presentationTheme), maybeAccentColor: navigationBar.accentTextColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkButtonPallete() -> TGCheckButtonPallete! {
|
func checkButtonPallete() -> TGCheckButtonPallete! {
|
||||||
|
|||||||
@ -105,7 +105,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo
|
|||||||
$0.item(context: context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, secureIdContext: strongSelf.secureIdContext, delete: { resource in
|
$0.item(context: context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, secureIdContext: strongSelf.secureIdContext, delete: { resource in
|
||||||
self?.deleteItem(resource)
|
self?.deleteItem(resource)
|
||||||
})
|
})
|
||||||
}), centralItemIndex: centralIndex, keepFirst: false)
|
}), centralItemIndex: centralIndex)
|
||||||
|
|
||||||
let ready = (strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void()))) |> afterNext { [weak strongSelf] _ in
|
let ready = (strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void()))) |> afterNext { [weak strongSelf] _ in
|
||||||
strongSelf?.didSetReady = true
|
strongSelf?.didSetReady = true
|
||||||
|
|||||||
@ -39,7 +39,7 @@ class SecureIdDocumentGalleryItem: GalleryItem {
|
|||||||
self.delete = delete
|
self.delete = delete
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = SecureIdDocumentGalleryItemNode(context: self.context, theme: self.theme, strings: self.strings)
|
let node = SecureIdDocumentGalleryItemNode(context: self.context, theme: self.theme, strings: self.strings)
|
||||||
|
|
||||||
node.setResource(secureIdContext: self.secureIdContext, resource: self.resource)
|
node.setResource(secureIdContext: self.secureIdContext, resource: self.resource)
|
||||||
@ -52,7 +52,7 @@ class SecureIdDocumentGalleryItem: GalleryItem {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? SecureIdDocumentGalleryItemNode {
|
if let node = node as? SecureIdDocumentGalleryItemNode {
|
||||||
node._title.set(.single(self.strings.Items_NOfM("\(self.location.position + 1)", "\(self.location.totalCount)").0))
|
node._title.set(.single(self.strings.Items_NOfM("\(self.location.position + 1)", "\(self.location.totalCount)").0))
|
||||||
|
|
||||||
|
|||||||
@ -223,6 +223,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
self.disposable.set(combineLatest(entriesSignal, self.animatedIn.get()).start(next: { [weak self] entries, animatedIn in
|
self.disposable.set(combineLatest(entriesSignal, self.animatedIn.get()).start(next: { [weak self] entries, animatedIn in
|
||||||
let f: () -> Void = {
|
let f: () -> Void = {
|
||||||
if let strongSelf = self, animatedIn {
|
if let strongSelf = self, animatedIn {
|
||||||
|
let isFirstTime = strongSelf.entries.isEmpty
|
||||||
strongSelf.entries = entries
|
strongSelf.entries = entries
|
||||||
if strongSelf.centralEntryIndex == nil {
|
if strongSelf.centralEntryIndex == nil {
|
||||||
strongSelf.centralEntryIndex = 0
|
strongSelf.centralEntryIndex = 0
|
||||||
@ -248,7 +249,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
} : nil, setMain: { [weak self] in
|
} : nil, setMain: { [weak self] in
|
||||||
self?.setMainEntry(entry)
|
self?.setMainEntry(entry)
|
||||||
})
|
})
|
||||||
}), centralItemIndex: 0, keepFirst: false)
|
}), centralItemIndex: 0, synchronous: !isFirstTime)
|
||||||
|
|
||||||
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
||||||
strongSelf?.didSetReady = true
|
strongSelf?.didSetReady = true
|
||||||
@ -597,7 +598,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
} else {
|
} else {
|
||||||
if let index = self.entries.firstIndex(of: entry) {
|
if let index = self.entries.firstIndex(of: entry) {
|
||||||
self.entries.remove(at: index)
|
self.entries.remove(at: index)
|
||||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,7 +612,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
} else {
|
} else {
|
||||||
if let index = self.entries.firstIndex(of: entry) {
|
if let index = self.entries.firstIndex(of: entry) {
|
||||||
self.entries.remove(at: index)
|
self.entries.remove(at: index)
|
||||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -625,7 +626,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
} else {
|
} else {
|
||||||
if let index = self.entries.firstIndex(of: entry) {
|
if let index = self.entries.firstIndex(of: entry) {
|
||||||
self.entries.remove(at: index)
|
self.entries.remove(at: index)
|
||||||
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1))
|
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,27 +65,27 @@ class PeerAvatarImageGalleryItem: GalleryItem {
|
|||||||
self.setMain = setMain
|
self.setMain = setMain
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = PeerAvatarImageGalleryItemNode(context: self.context, presentationData: self.presentationData, peer: self.peer, sourceHasRoundCorners: self.sourceHasRoundCorners)
|
let node = PeerAvatarImageGalleryItemNode(context: self.context, presentationData: self.presentationData, peer: self.peer, sourceHasRoundCorners: self.sourceHasRoundCorners)
|
||||||
|
|
||||||
if let indexData = self.entry.indexData {
|
if let indexData = self.entry.indexData {
|
||||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
||||||
}
|
}
|
||||||
|
|
||||||
node.setEntry(self.entry)
|
node.setEntry(self.entry, synchronous: synchronous)
|
||||||
node.footerContentNode.delete = self.delete
|
node.footerContentNode.delete = self.delete
|
||||||
node.footerContentNode.setMain = self.setMain
|
node.footerContentNode.setMain = self.setMain
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? PeerAvatarImageGalleryItemNode {
|
if let node = node as? PeerAvatarImageGalleryItemNode {
|
||||||
if let indexData = self.entry.indexData {
|
if let indexData = self.entry.indexData {
|
||||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
|
||||||
}
|
}
|
||||||
|
|
||||||
node.setEntry(self.entry)
|
node.setEntry(self.entry, synchronous: synchronous)
|
||||||
node.footerContentNode.delete = self.delete
|
node.footerContentNode.delete = self.delete
|
||||||
node.footerContentNode.setMain = self.setMain
|
node.footerContentNode.setMain = self.setMain
|
||||||
}
|
}
|
||||||
@ -201,7 +201,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(), size: statusSize))
|
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(), size: statusSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func setEntry(_ entry: AvatarGalleryEntry) {
|
fileprivate func setEntry(_ entry: AvatarGalleryEntry, synchronous: Bool) {
|
||||||
if self.entry != entry {
|
if self.entry != entry {
|
||||||
self.entry = entry
|
self.entry = entry
|
||||||
|
|
||||||
@ -224,7 +224,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
case let .image(_, _, imageRepresentations, _, _, _, _, _):
|
case let .image(_, _, imageRepresentations, _, _, _, _, _):
|
||||||
representations = imageRepresentations
|
representations = imageRepresentations
|
||||||
}
|
}
|
||||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations), dispatchOnDisplayLink: false)
|
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations, attemptSynchronously: synchronous), attemptSynchronously: synchronous, dispatchOnDisplayLink: false)
|
||||||
self.zoomableContent = (largestSize.dimensions.cgSize, self.contentNode)
|
self.zoomableContent = (largestSize.dimensions.cgSize, self.contentNode)
|
||||||
|
|
||||||
if let largestIndex = representations.firstIndex(where: { $0.representation == largestSize }) {
|
if let largestIndex = representations.firstIndex(where: { $0.representation == largestSize }) {
|
||||||
@ -278,8 +278,8 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
}
|
}
|
||||||
if let video = entry.videoRepresentations.last, let id = id {
|
if let video = entry.videoRepresentations.last, let id = id {
|
||||||
let mediaManager = self.context.sharedContext.mediaManager
|
let mediaManager = self.context.sharedContext.mediaManager
|
||||||
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||||
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
|
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
|
||||||
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
||||||
videoNode.isUserInteractionEnabled = false
|
videoNode.isUserInteractionEnabled = false
|
||||||
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
||||||
|
|||||||
@ -774,7 +774,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi
|
|||||||
if let profileImage = peer?.smallProfileImage {
|
if let profileImage = peer?.smallProfileImage {
|
||||||
return $0.withUpdatedUpdatingAvatar(.image(profileImage, false))
|
return $0.withUpdatedUpdatingAvatar(.image(profileImage, false))
|
||||||
} else {
|
} else {
|
||||||
return $0.withUpdatedUpdatingAvatar(.none)
|
return $0.withUpdatedUpdatingAvatar(ItemListAvatarAndNameInfoItemUpdatingAvatar.none)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateAvatarDisposable.set((updatePeerPhoto(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, accountPeerId: context.account.peerId, peerId: peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in
|
updateAvatarDisposable.set((updatePeerPhoto(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, accountPeerId: context.account.peerId, peerId: peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||||
|
|||||||
@ -628,7 +628,7 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
|||||||
if let profileImage = peer?.smallProfileImage {
|
if let profileImage = peer?.smallProfileImage {
|
||||||
return $0.withUpdatedUpdatingAvatar(.image(profileImage, false))
|
return $0.withUpdatedUpdatingAvatar(.image(profileImage, false))
|
||||||
} else {
|
} else {
|
||||||
return $0.withUpdatedUpdatingAvatar(.none)
|
return $0.withUpdatedUpdatingAvatar(ItemListAvatarAndNameInfoItemUpdatingAvatar.none)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateAvatarDisposable.set((updateAccountPhoto(account: context.account, resource: nil, videoResource: nil, mapResourceToAvatarSizes: { resource, representations in
|
updateAvatarDisposable.set((updateAccountPhoto(account: context.account, resource: nil, videoResource: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||||
|
|||||||
@ -301,7 +301,7 @@ public class WallpaperGalleryController: ViewController {
|
|||||||
updateItems.append(item)
|
updateItems.append(item)
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
return GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: updateItems, focusOnItem: self.galleryNode.pager.centralItemNode()?.index)
|
return GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: updateItems, focusOnItem: self.galleryNode.pager.centralItemNode()?.index, synchronous: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
|
|||||||
@ -51,13 +51,13 @@ class WallpaperGalleryItem: GalleryItem {
|
|||||||
self.source = source
|
self.source = source
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = WallpaperGalleryItemNode(context: self.context)
|
let node = WallpaperGalleryItemNode(context: self.context)
|
||||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? WallpaperGalleryItemNode {
|
if let node = node as? WallpaperGalleryItemNode {
|
||||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,19 +122,21 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
|||||||
public let sizeSpec: String
|
public let sizeSpec: String
|
||||||
public let volumeId: Int64
|
public let volumeId: Int64
|
||||||
public let localId: Int32
|
public let localId: Int32
|
||||||
|
public let size: Int?
|
||||||
public let fileReference: Data?
|
public let fileReference: Data?
|
||||||
|
|
||||||
public var id: MediaResourceId {
|
public var id: MediaResourceId {
|
||||||
return CloudPhotoSizeMediaResourceId(datacenterId: Int32(self.datacenterId), photoId: self.photoId, sizeSpec: self.sizeSpec)
|
return CloudPhotoSizeMediaResourceId(datacenterId: Int32(self.datacenterId), photoId: self.photoId, sizeSpec: self.sizeSpec)
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(datacenterId: Int32, photoId: Int64, accessHash: Int64, sizeSpec: String, volumeId: Int64, localId: Int32, fileReference: Data?) {
|
public init(datacenterId: Int32, photoId: Int64, accessHash: Int64, sizeSpec: String, volumeId: Int64, localId: Int32, size: Int?, fileReference: Data?) {
|
||||||
self.datacenterId = Int(datacenterId)
|
self.datacenterId = Int(datacenterId)
|
||||||
self.photoId = photoId
|
self.photoId = photoId
|
||||||
self.accessHash = accessHash
|
self.accessHash = accessHash
|
||||||
self.sizeSpec = sizeSpec
|
self.sizeSpec = sizeSpec
|
||||||
self.volumeId = volumeId
|
self.volumeId = volumeId
|
||||||
self.localId = localId
|
self.localId = localId
|
||||||
|
self.size = size
|
||||||
self.fileReference = fileReference
|
self.fileReference = fileReference
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +147,11 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
|||||||
self.sizeSpec = decoder.decodeStringForKey("s", orElse: "")
|
self.sizeSpec = decoder.decodeStringForKey("s", orElse: "")
|
||||||
self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0)
|
self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0)
|
||||||
self.localId = decoder.decodeInt32ForKey("l", orElse: 0)
|
self.localId = decoder.decodeInt32ForKey("l", orElse: 0)
|
||||||
|
if let size = decoder.decodeOptionalInt32ForKey("n") {
|
||||||
|
self.size = Int(size)
|
||||||
|
} else {
|
||||||
|
self.size = nil
|
||||||
|
}
|
||||||
self.fileReference = decoder.decodeBytesForKey("fr")?.makeData()
|
self.fileReference = decoder.decodeBytesForKey("fr")?.makeData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +162,11 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
|||||||
encoder.encodeString(self.sizeSpec, forKey: "s")
|
encoder.encodeString(self.sizeSpec, forKey: "s")
|
||||||
encoder.encodeInt64(self.volumeId, forKey: "v")
|
encoder.encodeInt64(self.volumeId, forKey: "v")
|
||||||
encoder.encodeInt32(self.localId, forKey: "l")
|
encoder.encodeInt32(self.localId, forKey: "l")
|
||||||
|
if let size = self.size {
|
||||||
|
encoder.encodeInt32(Int32(size), forKey: "n")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "n")
|
||||||
|
}
|
||||||
if let fileReference = self.fileReference {
|
if let fileReference = self.fileReference {
|
||||||
encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr")
|
encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr")
|
||||||
} else {
|
} else {
|
||||||
@ -164,7 +176,7 @@ public final class CloudPhotoSizeMediaResource: TelegramMediaResource {
|
|||||||
|
|
||||||
public func isEqual(to: MediaResource) -> Bool {
|
public func isEqual(to: MediaResource) -> Bool {
|
||||||
if let to = to as? CloudPhotoSizeMediaResource {
|
if let to = to as? CloudPhotoSizeMediaResource {
|
||||||
return self.datacenterId == to.datacenterId && self.photoId == to.photoId && self.accessHash == to.accessHash && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId && self.fileReference == to.fileReference
|
return self.datacenterId == to.datacenterId && self.photoId == to.photoId && self.accessHash == to.accessHash && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId && self.size == to.size && self.fileReference == to.fileReference
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,12 +125,13 @@ public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateMan
|
|||||||
|> mapError { _ in return UploadPeerPhotoError.generic }
|
|> mapError { _ in return UploadPeerPhotoError.generic }
|
||||||
|> mapToSignal { photo -> Signal<(UpdatePeerPhotoStatus, MediaResource?), UploadPeerPhotoError> in
|
|> mapToSignal { photo -> Signal<(UpdatePeerPhotoStatus, MediaResource?), UploadPeerPhotoError> in
|
||||||
var representations: [TelegramMediaImageRepresentation] = []
|
var representations: [TelegramMediaImageRepresentation] = []
|
||||||
|
var videoRepresentations: [TelegramMediaImage.VideoRepresentation] = []
|
||||||
switch photo {
|
switch photo {
|
||||||
case let .photo(photo: apiPhoto, users: _):
|
case let .photo(photo: apiPhoto, users: _):
|
||||||
switch apiPhoto {
|
switch apiPhoto {
|
||||||
case .photoEmpty:
|
case .photoEmpty:
|
||||||
break
|
break
|
||||||
case let .photo(_, _, _, _, _, sizes, videoSizes, dcId):
|
case let .photo(_, id, accessHash, fileReference, _, sizes, videoSizes, dcId):
|
||||||
var sizes = sizes
|
var sizes = sizes
|
||||||
if sizes.count == 3 {
|
if sizes.count == 3 {
|
||||||
sizes.remove(at: 1)
|
sizes.remove(at: 1)
|
||||||
@ -147,14 +148,32 @@ public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateMan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let resource = photoResult.resource as? LocalFileReferenceMediaResource {
|
if let videoSizes = videoSizes {
|
||||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) {
|
for size in videoSizes {
|
||||||
for representation in representations {
|
switch size {
|
||||||
postbox.mediaBox.storeResourceData(representation.resource.id, data: data)
|
case let .videoSize(type, location, w, h, size):
|
||||||
|
let resource: TelegramMediaResource
|
||||||
|
switch location {
|
||||||
|
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||||
|
resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: Int(size), fileReference: fileReference.makeData())
|
||||||
|
}
|
||||||
|
|
||||||
|
videoRepresentations.append(TelegramMediaImage.VideoRepresentation(
|
||||||
|
dimensions: PixelDimensions(width: w, height: h),
|
||||||
|
resource: resource))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for representation in representations {
|
||||||
|
postbox.mediaBox.copyResourceData(from: photoResult.resource.id, to: representation.resource.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let resource = videoResult?.resource {
|
||||||
|
for representation in videoRepresentations {
|
||||||
|
postbox.mediaBox.copyResourceData(from: resource.id, to: representation.resource.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return postbox.transaction { transaction -> (UpdatePeerPhotoStatus, MediaResource?) in
|
return postbox.transaction { transaction -> (UpdatePeerPhotoStatus, MediaResource?) in
|
||||||
@ -221,7 +240,7 @@ public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateMan
|
|||||||
switch result {
|
switch result {
|
||||||
case let .complete(representations):
|
case let .complete(representations):
|
||||||
if let resource = resource as? LocalFileReferenceMediaResource {
|
if let resource = resource as? LocalFileReferenceMediaResource {
|
||||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) {
|
if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath), options: [.mappedRead] ) {
|
||||||
for representation in representations {
|
for representation in representations {
|
||||||
postbox.mediaBox.storeResourceData(representation.resource.id, data: data)
|
postbox.mediaBox.storeResourceData(representation.resource.id, data: data)
|
||||||
}
|
}
|
||||||
@ -284,16 +303,10 @@ public func updatePeerPhotoExisting(network: Network, reference: TelegramMediaIm
|
|||||||
|> `catch` { _ -> Signal<Api.UserProfilePhoto, NoError> in
|
|> `catch` { _ -> Signal<Api.UserProfilePhoto, NoError> in
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
|
||||||
return network.request(Api.functions.photos.deletePhotos(id: [.inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))]))
|
|
||||||
|> `catch` { _ -> Signal<[Int64], NoError> in
|
|
||||||
return .single([])
|
|
||||||
}
|
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeAccountPhoto(network: Network, reference: TelegramMediaImageReference?) -> Signal<Void, NoError> {
|
public func removeAccountPhoto(network: Network, reference: TelegramMediaImageReference?) -> Signal<Void, NoError> {
|
||||||
|
|||||||
@ -12,13 +12,13 @@ func telegramMediaImageRepresentationsFromApiSizes(datacenterId: Int32, photoId:
|
|||||||
case let .photoCachedSize(type, location, w, h, _):
|
case let .photoCachedSize(type, location, w, h, _):
|
||||||
switch location {
|
switch location {
|
||||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||||
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference)
|
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: nil, fileReference: fileReference)
|
||||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource))
|
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource))
|
||||||
}
|
}
|
||||||
case let .photoSize(type, location, w, h, _):
|
case let .photoSize(type, location, w, h, size):
|
||||||
switch location {
|
switch location {
|
||||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||||
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference)
|
let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: Int(size), fileReference: fileReference)
|
||||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource))
|
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource))
|
||||||
}
|
}
|
||||||
case let .photoStrippedSize(_, data):
|
case let .photoStrippedSize(_, data):
|
||||||
@ -44,11 +44,11 @@ func telegramMediaImageFromApiPhoto(_ photo: Api.Photo) -> TelegramMediaImage? {
|
|||||||
if let videoSizes = videoSizes {
|
if let videoSizes = videoSizes {
|
||||||
for size in videoSizes {
|
for size in videoSizes {
|
||||||
switch size {
|
switch size {
|
||||||
case let .videoSize(type, location, w, h, _):
|
case let .videoSize(type, location, w, h, size):
|
||||||
let resource: TelegramMediaResource
|
let resource: TelegramMediaResource
|
||||||
switch location {
|
switch location {
|
||||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||||
resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference.makeData())
|
resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: Int(size), fileReference: fileReference.makeData())
|
||||||
}
|
}
|
||||||
|
|
||||||
videoRepresentations.append(TelegramMediaImage.VideoRepresentation(
|
videoRepresentations.append(TelegramMediaImage.VideoRepresentation(
|
||||||
|
|||||||
@ -12,7 +12,7 @@ private func collectPreCachedResources(for photo: Api.Photo) -> [(MediaResource,
|
|||||||
case let .photoCachedSize(type, location, _, _, bytes):
|
case let .photoCachedSize(type, location, _, _, bytes):
|
||||||
switch location {
|
switch location {
|
||||||
case let .fileLocationToBeDeprecated(volumeId, localId):
|
case let .fileLocationToBeDeprecated(volumeId, localId):
|
||||||
let resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference.makeData())
|
let resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, size: nil, fileReference: fileReference.makeData())
|
||||||
let data = bytes.makeData()
|
let data = bytes.makeData()
|
||||||
return [(resource, data)]
|
return [(resource, data)]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,10 @@ import TelegramUIPreferences
|
|||||||
|
|
||||||
private func decodeColor<Key>(_ values: KeyedDecodingContainer<Key>, _ key: Key, decoder: Decoder? = nil, fallbackKey: String? = nil) throws -> UIColor {
|
private func decodeColor<Key>(_ values: KeyedDecodingContainer<Key>, _ key: Key, decoder: Decoder? = nil, fallbackKey: String? = nil) throws -> UIColor {
|
||||||
if let decoder = decoder as? PresentationThemeDecoding, let fallbackKey = fallbackKey {
|
if let decoder = decoder as? PresentationThemeDecoding, let fallbackKey = fallbackKey {
|
||||||
let key = (decoder.codingPath.map { $0.stringValue } + [key.stringValue]).joined(separator: ".")
|
var codingPath = decoder.codingPath.map { $0.stringValue }
|
||||||
|
codingPath.append(key.stringValue)
|
||||||
|
|
||||||
|
let key = codingPath.joined(separator: ".")
|
||||||
decoder.fallbackKeys[key] = fallbackKey
|
decoder.fallbackKeys[key] = fallbackKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1021,9 +1024,17 @@ extension PresentationThemeBubbleColorComponents: Codable {
|
|||||||
public convenience init(from decoder: Decoder) throws {
|
public convenience init(from decoder: Decoder) throws {
|
||||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let codingPath = decoder.codingPath.map { $0.stringValue }.joined(separator: ".")
|
let codingPath = decoder.codingPath.map { $0.stringValue }.joined(separator: ".")
|
||||||
|
|
||||||
|
var fillColor = try decodeColor(values, .bg)
|
||||||
|
var gradientColor = try decodeColor(values, .gradientBg, decoder: decoder, fallbackKey: "\(codingPath).bg")
|
||||||
|
if gradientColor.rgb != fillColor.rgb {
|
||||||
|
fillColor = fillColor.withAlphaComponent(1.0)
|
||||||
|
gradientColor = gradientColor.withAlphaComponent(1.0)
|
||||||
|
}
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
fill: try decodeColor(values, .bg),
|
fill: fillColor,
|
||||||
gradientFill: try decodeColor(values, .gradientBg, decoder: decoder, fallbackKey: codingPath + ".bg"),
|
gradientFill: gradientColor,
|
||||||
highlightedFill: try decodeColor(values, .highlightedBg),
|
highlightedFill: try decodeColor(values, .highlightedBg),
|
||||||
stroke: try decodeColor(values, .stroke),
|
stroke: try decodeColor(values, .stroke),
|
||||||
shadow: try? values.decode(PresentationThemeBubbleShadow.self, forKey: .shadow)
|
shadow: try? values.decode(PresentationThemeBubbleShadow.self, forKey: .shadow)
|
||||||
@ -1162,7 +1173,7 @@ extension PresentationThemePartedColors: Codable {
|
|||||||
accentControlDisabledColor: (try? decodeColor(values, .accentControlDisabled)) ?? accentControlColor.withAlphaComponent(0.5),
|
accentControlDisabledColor: (try? decodeColor(values, .accentControlDisabled)) ?? accentControlColor.withAlphaComponent(0.5),
|
||||||
mediaActiveControlColor: try decodeColor(values, .mediaActiveControl),
|
mediaActiveControlColor: try decodeColor(values, .mediaActiveControl),
|
||||||
mediaInactiveControlColor: try decodeColor(values, .mediaInactiveControl),
|
mediaInactiveControlColor: try decodeColor(values, .mediaInactiveControl),
|
||||||
mediaControlInnerBackgroundColor: try decodeColor(values, .mediaControlInnerBg, decoder: decoder, fallbackKey: codingPath + ".bubble.withWp.bg"),
|
mediaControlInnerBackgroundColor: try decodeColor(values, .mediaControlInnerBg, decoder: decoder, fallbackKey: "\(codingPath).bubble.withWp.bg"),
|
||||||
pendingActivityColor: try decodeColor(values, .pendingActivity),
|
pendingActivityColor: try decodeColor(values, .pendingActivity),
|
||||||
fileTitleColor: try decodeColor(values, .fileTitle),
|
fileTitleColor: try decodeColor(values, .fileTitle),
|
||||||
fileDescriptionColor: try decodeColor(values, .fileDescription),
|
fileDescriptionColor: try decodeColor(values, .fileDescription),
|
||||||
@ -1389,7 +1400,7 @@ extension PresentationThemeChatInputPanel: Codable {
|
|||||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let codingPath = decoder.codingPath.map { $0.stringValue }.joined(separator: ".")
|
let codingPath = decoder.codingPath.map { $0.stringValue }.joined(separator: ".")
|
||||||
self.init(panelBackgroundColor: try decodeColor(values, .panelBg),
|
self.init(panelBackgroundColor: try decodeColor(values, .panelBg),
|
||||||
panelBackgroundColorNoWallpaper: try decodeColor(values, .panelBg, decoder: decoder, fallbackKey: codingPath + ".panelBgNoWallpaper"),
|
panelBackgroundColorNoWallpaper: try decodeColor(values, .panelBg, decoder: decoder, fallbackKey: "\(codingPath).panelBgNoWallpaper"),
|
||||||
panelSeparatorColor: try decodeColor(values, .panelSeparator),
|
panelSeparatorColor: try decodeColor(values, .panelSeparator),
|
||||||
panelControlAccentColor: try decodeColor(values, .panelControlAccent),
|
panelControlAccentColor: try decodeColor(values, .panelControlAccent),
|
||||||
panelControlColor: try decodeColor(values, .panelControl),
|
panelControlColor: try decodeColor(values, .panelControl),
|
||||||
|
|||||||
@ -182,12 +182,20 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isExpanded: Bool = false {
|
||||||
|
didSet {
|
||||||
|
self.videoNode?.canAttachContent = self.isExpanded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init(context: AccountContext) {
|
init(context: AccountContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.imageNode = TransformImageNode()
|
self.imageNode = TransformImageNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
|
self.clipsToBounds = true
|
||||||
|
|
||||||
self.imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
self.imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||||
self.addSubnode(self.imageNode)
|
self.addSubnode(self.imageNode)
|
||||||
|
|
||||||
@ -222,8 +230,8 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let video = videoRepresentations.last, let id = id {
|
if let video = videoRepresentations.last, let id = id {
|
||||||
let mediaManager = self.context.sharedContext.mediaManager
|
let mediaManager = self.context.sharedContext.mediaManager
|
||||||
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||||
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
|
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
|
||||||
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
||||||
videoNode.isUserInteractionEnabled = false
|
videoNode.isUserInteractionEnabled = false
|
||||||
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
||||||
@ -259,7 +267,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
|||||||
videoNode.updateLayout(size: imageSize, transition: .immediate)
|
videoNode.updateLayout(size: imageSize, transition: .immediate)
|
||||||
videoNode.frame = imageFrame
|
videoNode.frame = imageFrame
|
||||||
|
|
||||||
videoNode.canAttachContent = true
|
videoNode.canAttachContent = self.isExpanded
|
||||||
if videoNode.hasAttachedContext {
|
if videoNode.hasAttachedContext {
|
||||||
videoNode.play()
|
videoNode.play()
|
||||||
}
|
}
|
||||||
@ -285,17 +293,17 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
private var items: [PeerInfoAvatarListItem] = []
|
private var items: [PeerInfoAvatarListItem] = []
|
||||||
private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:]
|
private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:]
|
||||||
private var stripNodes: [ASImageNode] = []
|
private var stripNodes: [ASImageNode] = []
|
||||||
private var stripWidth: CGFloat = 0.0
|
|
||||||
private let activeStripImage: UIImage
|
private let activeStripImage: UIImage
|
||||||
private var appliedStripNodeCurrentIndex: Int?
|
private var appliedStripNodeCurrentIndex: Int?
|
||||||
private var currentIndex: Int = 0
|
private var currentIndex: Int = 0
|
||||||
private var transitionFraction: CGFloat = 0.0
|
private var transitionFraction: CGFloat = 0.0
|
||||||
|
|
||||||
private var validLayout: CGSize?
|
private var validLayout: CGSize?
|
||||||
|
private var isExpanded = false
|
||||||
|
|
||||||
private let disposable = MetaDisposable()
|
private let disposable = MetaDisposable()
|
||||||
private let positionDisposable = MetaDisposable()
|
|
||||||
private var initializedList = false
|
private var initializedList = false
|
||||||
|
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
|
||||||
|
|
||||||
let isReady = Promise<Bool>()
|
let isReady = Promise<Bool>()
|
||||||
private var didSetReady = false
|
private var didSetReady = false
|
||||||
@ -316,55 +324,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var playerUpdateTimer: SwiftSignalKit.Timer?
|
|
||||||
private var playerStatus: MediaPlayerStatus? {
|
|
||||||
didSet {
|
|
||||||
if self.playerStatus != oldValue {
|
|
||||||
if let playerStatus = playerStatus, case .playing = playerStatus.status {
|
|
||||||
self.ensureHasTimer()
|
|
||||||
} else {
|
|
||||||
self.stopTimer()
|
|
||||||
}
|
|
||||||
self.updateStatus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func ensureHasTimer() {
|
|
||||||
if self.playerUpdateTimer == nil {
|
|
||||||
let timer = SwiftSignalKit.Timer(timeout: 0.016, repeat: true, completion: { [weak self] in
|
|
||||||
self?.updateStatus()
|
|
||||||
}, queue: Queue.mainQueue())
|
|
||||||
self.playerUpdateTimer = timer
|
|
||||||
timer.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateStatus() {
|
|
||||||
var position: CGFloat = 1.0
|
|
||||||
if let playerStatus = self.playerStatus {
|
|
||||||
var playerPosition: Double
|
|
||||||
if !playerStatus.generationTimestamp.isZero, case .playing = playerStatus.status {
|
|
||||||
playerPosition = playerStatus.timestamp + (CACurrentMediaTime() - playerStatus.generationTimestamp)
|
|
||||||
} else {
|
|
||||||
playerPosition = playerStatus.timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
position = CGFloat(playerPosition / playerStatus.duration)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let appliedStripNodeCurrentIndex = self.appliedStripNodeCurrentIndex {
|
|
||||||
var frame = self.stripNodes[appliedStripNodeCurrentIndex].frame
|
|
||||||
frame.size.width = self.stripWidth * position
|
|
||||||
self.stripNodes[appliedStripNodeCurrentIndex].frame = frame
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func stopTimer() {
|
|
||||||
self.playerUpdateTimer?.invalidate()
|
|
||||||
self.playerUpdateTimer = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
init(context: AccountContext) {
|
init(context: AccountContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
@ -537,7 +496,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.disposable.dispose()
|
self.disposable.dispose()
|
||||||
self.positionDisposable.dispose()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
@ -628,8 +586,9 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(size: CGSize, peer: Peer?, transition: ContainedViewLayoutTransition) {
|
func update(size: CGSize, peer: Peer?, isExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = size
|
self.validLayout = size
|
||||||
|
self.isExpanded = isExpanded
|
||||||
|
|
||||||
self.leftHighlightNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height))
|
self.leftHighlightNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height))
|
||||||
self.rightHighlightNode.frame = CGRect(origin: CGPoint(x: size.width - floor(size.width * 1.0 / 5.0), y: 0.0), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height))
|
self.rightHighlightNode.frame = CGRect(origin: CGPoint(x: size.width - floor(size.width * 1.0 / 5.0), y: 0.0), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height))
|
||||||
@ -652,6 +611,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
strongSelf.galleryEntries = entries
|
strongSelf.galleryEntries = entries
|
||||||
strongSelf.items = items
|
strongSelf.items = items
|
||||||
|
strongSelf.itemsUpdated?(items)
|
||||||
if let size = strongSelf.validLayout {
|
if let size = strongSelf.validLayout {
|
||||||
strongSelf.updateItems(size: size, transition: .immediate, stripTransition: .immediate)
|
strongSelf.updateItems(size: size, transition: .immediate, stripTransition: .immediate)
|
||||||
}
|
}
|
||||||
@ -677,9 +637,11 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
var wasAdded = false
|
var wasAdded = false
|
||||||
if let current = self.itemNodes[self.items[i].id] {
|
if let current = self.itemNodes[self.items[i].id] {
|
||||||
itemNode = current
|
itemNode = current
|
||||||
|
itemNode.isExpanded = self.isExpanded
|
||||||
} else {
|
} else {
|
||||||
wasAdded = true
|
wasAdded = true
|
||||||
itemNode = PeerInfoAvatarListItemNode(context: self.context)
|
itemNode = PeerInfoAvatarListItemNode(context: self.context)
|
||||||
|
itemNode.isExpanded = self.isExpanded
|
||||||
itemNode.setup(item: self.items[i], synchronous: synchronous && i == self.currentIndex)
|
itemNode.setup(item: self.items[i], synchronous: synchronous && i == self.currentIndex)
|
||||||
self.itemNodes[self.items[i].id] = itemNode
|
self.itemNodes[self.items[i].id] = itemNode
|
||||||
self.contentNode.addSubnode(itemNode)
|
self.contentNode.addSubnode(itemNode)
|
||||||
@ -687,6 +649,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
let indexOffset = CGFloat(i - self.currentIndex)
|
let indexOffset = CGFloat(i - self.currentIndex)
|
||||||
let itemFrame = CGRect(origin: CGPoint(x: indexOffset * size.width + self.transitionFraction * size.width - size.width / 2.0, y: -size.height / 2.0), size: size)
|
let itemFrame = CGRect(origin: CGPoint(x: indexOffset * size.width + self.transitionFraction * size.width - size.width / 2.0, y: -size.height / 2.0), size: size)
|
||||||
|
|
||||||
|
|
||||||
if wasAdded {
|
if wasAdded {
|
||||||
addedItemNodesForAdditiveTransition.append(itemNode)
|
addedItemNodesForAdditiveTransition.append(itemNode)
|
||||||
itemNode.frame = itemFrame
|
itemNode.frame = itemFrame
|
||||||
@ -748,17 +711,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
if self.currentIndex >= 0 && self.currentIndex < self.stripNodes.count {
|
if self.currentIndex >= 0 && self.currentIndex < self.stripNodes.count {
|
||||||
self.stripNodes[self.currentIndex].alpha = 1.0
|
self.stripNodes[self.currentIndex].alpha = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
if let currentItemNode = self.currentItemNode {
|
|
||||||
self.positionDisposable.set((currentItemNode.mediaStatus
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.playerStatus = status
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
self.positionDisposable.set(nil)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if hadOneStripNode && self.stripNodes.count > 1 {
|
if hadOneStripNode && self.stripNodes.count > 1 {
|
||||||
self.stripContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
self.stripContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||||
@ -766,7 +718,6 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
let stripInset: CGFloat = 8.0
|
let stripInset: CGFloat = 8.0
|
||||||
let stripSpacing: CGFloat = 4.0
|
let stripSpacing: CGFloat = 4.0
|
||||||
let stripWidth: CGFloat = max(5.0, floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count)))
|
let stripWidth: CGFloat = max(5.0, floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count)))
|
||||||
self.stripWidth = stripWidth
|
|
||||||
let currentStripMinX = stripInset + CGFloat(self.currentIndex) * (stripWidth + stripSpacing)
|
let currentStripMinX = stripInset + CGFloat(self.currentIndex) * (stripWidth + stripSpacing)
|
||||||
let currentStripMidX = floor(currentStripMinX + stripWidth / 2.0)
|
let currentStripMidX = floor(currentStripMinX + stripWidth / 2.0)
|
||||||
let lastStripMaxX = stripInset + CGFloat(self.stripNodes.count - 1) * (stripWidth + stripSpacing) + stripWidth
|
let lastStripMaxX = stripInset + CGFloat(self.stripNodes.count - 1) * (stripWidth + stripSpacing) + stripWidth
|
||||||
@ -795,6 +746,9 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let avatarNode: AvatarNode
|
let avatarNode: AvatarNode
|
||||||
|
|
||||||
|
private var videoNode: UniversalVideoNode?
|
||||||
|
private var videoContent: NativeVideoContent?
|
||||||
|
|
||||||
var tapped: (() -> Void)?
|
var tapped: (() -> Void)?
|
||||||
|
|
||||||
private var isFirstAvatarLoading = true
|
private var isFirstAvatarLoading = true
|
||||||
@ -818,7 +772,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(peer: Peer?, theme: PresentationTheme, avatarSize: CGFloat) {
|
func update(peer: Peer?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool) {
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
var overrideImage: AvatarNodeImageOverride?
|
var overrideImage: AvatarNodeImageOverride?
|
||||||
if peer.isDeleted {
|
if peer.isDeleted {
|
||||||
@ -829,6 +783,46 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.avatarNode.frame = CGRect(origin: CGPoint(x: -avatarSize / 2.0, y: -avatarSize / 2.0), size: CGSize(width: avatarSize, height: avatarSize))
|
self.avatarNode.frame = CGRect(origin: CGPoint(x: -avatarSize / 2.0, y: -avatarSize / 2.0), size: CGSize(width: avatarSize, height: avatarSize))
|
||||||
self.avatarNode.font = avatarPlaceholderFont(size: floor(avatarSize * 16.0 / 37.0))
|
self.avatarNode.font = avatarPlaceholderFont(size: floor(avatarSize * 16.0 / 37.0))
|
||||||
|
|
||||||
|
if let item = item, case let .image(reference, _, videoRepresentations) = item, let video = videoRepresentations.last, case let .cloud(imageId, _, _) = reference {
|
||||||
|
let id = imageId
|
||||||
|
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
|
||||||
|
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
|
||||||
|
if videoContent.id != self.videoContent?.id {
|
||||||
|
let mediaManager = self.context.sharedContext.mediaManager
|
||||||
|
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
|
||||||
|
videoNode.isUserInteractionEnabled = false
|
||||||
|
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.videoNode?.isHidden = !owns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.videoContent = videoContent
|
||||||
|
self.videoNode = videoNode
|
||||||
|
|
||||||
|
let maskPath = UIBezierPath(ovalIn: CGRect(origin: CGPoint(), size: self.avatarNode.frame.size))
|
||||||
|
let shape = CAShapeLayer()
|
||||||
|
shape.path = maskPath.cgPath
|
||||||
|
videoNode.layer.mask = shape
|
||||||
|
|
||||||
|
self.addSubnode(videoNode)
|
||||||
|
}
|
||||||
|
} else if let videoNode = self.videoNode {
|
||||||
|
self.videoContent = nil
|
||||||
|
self.videoNode = nil
|
||||||
|
|
||||||
|
videoNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
|
||||||
|
if let videoNode = self.videoNode {
|
||||||
|
videoNode.updateLayout(size: self.avatarNode.frame.size, transition: .immediate)
|
||||||
|
videoNode.frame = self.avatarNode.frame
|
||||||
|
|
||||||
|
videoNode.canAttachContent = !isExpanded
|
||||||
|
if videoNode.hasAttachedContext {
|
||||||
|
videoNode.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -922,6 +916,9 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
|
|
||||||
let isReady = Promise<Bool>()
|
let isReady = Promise<Bool>()
|
||||||
|
|
||||||
|
var arguments: (Peer?, PresentationTheme, CGFloat, Bool)?
|
||||||
|
var item: PeerInfoAvatarListItem?
|
||||||
|
|
||||||
init(context: AccountContext, readyWhenGalleryLoads: Bool) {
|
init(context: AccountContext, readyWhenGalleryLoads: Bool) {
|
||||||
self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context)
|
self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context)
|
||||||
self.listContainerTransformNode = ASDisplayNode()
|
self.listContainerTransformNode = ASDisplayNode()
|
||||||
@ -965,10 +962,20 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|> take(1))
|
|> take(1))
|
||||||
|
|
||||||
|
self.listContainerNode.itemsUpdated = { [weak self] items in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.item = items.first
|
||||||
|
if let (peer, theme, avatarSize, isExpanded) = strongSelf.arguments {
|
||||||
|
strongSelf.avatarContainerNode.update(peer: peer, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(size: CGSize, avatarSize: CGFloat, isExpanded: Bool, peer: Peer?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) {
|
func update(size: CGSize, avatarSize: CGFloat, isExpanded: Bool, peer: Peer?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) {
|
||||||
self.avatarContainerNode.update(peer: peer, theme: theme, avatarSize: avatarSize)
|
self.arguments = (peer, theme, avatarSize, isExpanded)
|
||||||
|
self.avatarContainerNode.update(peer: peer, item: self.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
@ -2073,7 +2080,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale)
|
transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.avatarListNode.listContainerNode.update(size: expandedAvatarListSize, peer: peer, transition: transition)
|
self.avatarListNode.listContainerNode.update(size: expandedAvatarListSize, peer: peer, isExpanded: self.isAvatarExpanded, transition: transition)
|
||||||
|
|
||||||
let panelWithAvatarHeight: CGFloat = 112.0 + avatarSize
|
let panelWithAvatarHeight: CGFloat = 112.0 + avatarSize
|
||||||
let buttonsCollapseStart = titleCollapseOffset
|
let buttonsCollapseStart = titleCollapseOffset
|
||||||
|
|||||||
@ -829,7 +829,9 @@ public func drawThemeImage(context c: CGContext, theme: PresentationTheme, wallp
|
|||||||
|
|
||||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 ")
|
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 ")
|
||||||
if incoming.fill.rgb != incoming.gradientFill.rgb {
|
if incoming.fill.rgb != incoming.gradientFill.rgb {
|
||||||
let gradientColors = [incoming.fill, incoming.gradientFill].map { $0.cgColor } as CFArray
|
c.clip()
|
||||||
|
|
||||||
|
let gradientColors = [incoming.fill.withAlphaComponent(1.0), incoming.gradientFill.withAlphaComponent(1.0)].map { $0.cgColor } as CFArray
|
||||||
var locations: [CGFloat] = [0.0, 1.0]
|
var locations: [CGFloat] = [0.0, 1.0]
|
||||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||||
@ -855,7 +857,7 @@ public func drawThemeImage(context c: CGContext, theme: PresentationTheme, wallp
|
|||||||
if outgoing.fill.rgb != outgoing.gradientFill.rgb {
|
if outgoing.fill.rgb != outgoing.gradientFill.rgb {
|
||||||
c.clip()
|
c.clip()
|
||||||
|
|
||||||
let gradientColors = [outgoing.fill, outgoing.gradientFill].map { $0.cgColor } as CFArray
|
let gradientColors = [outgoing.fill.withAlphaComponent(1.0), outgoing.gradientFill.withAlphaComponent(1.0)].map { $0.cgColor } as CFArray
|
||||||
var locations: [CGFloat] = [0.0, 1.0]
|
var locations: [CGFloat] = [0.0, 1.0]
|
||||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||||
|
|||||||
@ -139,7 +139,7 @@ class WebSearchGalleryController: ViewController {
|
|||||||
if strongSelf.isViewLoaded {
|
if strongSelf.isViewLoaded {
|
||||||
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
|
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
|
||||||
$0.item(context: context, presentationData: strongSelf.presentationData, controllerInteraction: strongSelf.controllerInteraction)
|
$0.item(context: context, presentationData: strongSelf.presentationData, controllerInteraction: strongSelf.controllerInteraction)
|
||||||
}), centralItemIndex: centralIndex, keepFirst: false)
|
}), centralItemIndex: centralIndex)
|
||||||
|
|
||||||
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
||||||
strongSelf?.didSetReady = true
|
strongSelf?.didSetReady = true
|
||||||
|
|||||||
@ -35,13 +35,13 @@ class WebSearchVideoGalleryItem: GalleryItem {
|
|||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
}
|
}
|
||||||
|
|
||||||
func node() -> GalleryItemNode {
|
func node(synchronous: Bool) -> GalleryItemNode {
|
||||||
let node = WebSearchVideoGalleryItemNode(context: self.context, presentationData: self.presentationData, controllerInteraction: self.controllerInteraction)
|
let node = WebSearchVideoGalleryItemNode(context: self.context, presentationData: self.presentationData, controllerInteraction: self.controllerInteraction)
|
||||||
node.setupItem(self)
|
node.setupItem(self)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(node: GalleryItemNode) {
|
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||||
if let node = node as? WebSearchVideoGalleryItemNode {
|
if let node = node as? WebSearchVideoGalleryItemNode {
|
||||||
node.setupItem(self)
|
node.setupItem(self)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user