mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
5afa9250aa
@ -197,6 +197,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let hasPendingStoriesPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
|
public var hasPendingStories: Signal<Bool, NoError> {
|
||||||
|
return self.hasPendingStoriesPromise.get()
|
||||||
|
}
|
||||||
|
|
||||||
private var storyProgressDisposable: Disposable?
|
private var storyProgressDisposable: Disposable?
|
||||||
private var storySubscriptionsDisposable: Disposable?
|
private var storySubscriptionsDisposable: Disposable?
|
||||||
private var preloadStorySubscriptionsDisposable: Disposable?
|
private var preloadStorySubscriptionsDisposable: Disposable?
|
||||||
@ -1956,6 +1961,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
self.maybeDisplayStoryTooltip()
|
self.maybeDisplayStoryTooltip()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.hasPendingStoriesPromise.set(rawStoryArchiveSubscriptions.accountItem?.hasPending ?? false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -803,7 +803,6 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
var ignoreStoryUnlockedScrolling: Bool = false
|
var ignoreStoryUnlockedScrolling: Bool = false
|
||||||
var tempTopInset: CGFloat = 0.0 {
|
var tempTopInset: CGFloat = 0.0 {
|
||||||
didSet {
|
didSet {
|
||||||
if self.tempTopInset != oldValue {
|
|
||||||
for (_, itemNode) in self.itemNodes {
|
for (_, itemNode) in self.itemNodes {
|
||||||
itemNode.listNode.tempTopInset = self.tempTopInset
|
itemNode.listNode.tempTopInset = self.tempTopInset
|
||||||
}
|
}
|
||||||
@ -812,7 +811,6 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var initialScrollingOffset: CGFloat?
|
var initialScrollingOffset: CGFloat?
|
||||||
|
|
||||||
@ -2022,6 +2020,8 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
var effectiveStorySubscriptions: EngineStorySubscriptions?
|
var effectiveStorySubscriptions: EngineStorySubscriptions?
|
||||||
if let controller = self.controller, let storySubscriptions = controller.orderedStorySubscriptions, shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions, isHidden: controller.location == .chatList(groupId: .archive)) {
|
if let controller = self.controller, let storySubscriptions = controller.orderedStorySubscriptions, shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions, isHidden: controller.location == .chatList(groupId: .archive)) {
|
||||||
effectiveStorySubscriptions = controller.orderedStorySubscriptions
|
effectiveStorySubscriptions = controller.orderedStorySubscriptions
|
||||||
|
} else {
|
||||||
|
effectiveStorySubscriptions = EngineStorySubscriptions(accountItem: nil, items: [], hasMoreToken: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let navigationBarSize = self.navigationBarView.update(
|
let navigationBarSize = self.navigationBarView.update(
|
||||||
@ -2699,6 +2699,7 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
func scrollToTopIfStoriesAreExpanded() {
|
func scrollToTopIfStoriesAreExpanded() {
|
||||||
if let contentOffset = self.mainContainerNode.contentOffset, case let .known(offset) = contentOffset, offset < 0.0 {
|
if let contentOffset = self.mainContainerNode.contentOffset, case let .known(offset) = contentOffset, offset < 0.0 {
|
||||||
self.mainContainerNode.scrollToTop(animated: true, adjustForTempInset: false)
|
self.mainContainerNode.scrollToTop(animated: true, adjustForTempInset: false)
|
||||||
|
self.mainContainerNode.tempTopInset = 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,6 +362,37 @@ public func stringForRelativeLiveLocationUpdateTimestamp(strings: PresentationSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func monthAtIndex(_ index: Int, strings: PresentationStrings) -> String {
|
||||||
|
switch index {
|
||||||
|
case 0:
|
||||||
|
return strings.Month_GenJanuary
|
||||||
|
case 1:
|
||||||
|
return strings.Month_GenFebruary
|
||||||
|
case 2:
|
||||||
|
return strings.Month_GenMarch
|
||||||
|
case 3:
|
||||||
|
return strings.Month_GenApril
|
||||||
|
case 4:
|
||||||
|
return strings.Month_GenMay
|
||||||
|
case 5:
|
||||||
|
return strings.Month_GenJune
|
||||||
|
case 6:
|
||||||
|
return strings.Month_GenJuly
|
||||||
|
case 7:
|
||||||
|
return strings.Month_GenAugust
|
||||||
|
case 8:
|
||||||
|
return strings.Month_GenSeptember
|
||||||
|
case 9:
|
||||||
|
return strings.Month_GenOctober
|
||||||
|
case 10:
|
||||||
|
return strings.Month_GenNovember
|
||||||
|
case 11:
|
||||||
|
return strings.Month_GenDecember
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func stringForRelativeActivityTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, preciseTime: Bool = false, relativeTimestamp: Int32, relativeTo timestamp: Int32) -> String {
|
public func stringForRelativeActivityTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, preciseTime: Bool = false, relativeTimestamp: Int32, relativeTo timestamp: Int32) -> String {
|
||||||
let difference = timestamp - relativeTimestamp
|
let difference = timestamp - relativeTimestamp
|
||||||
if difference < 60 {
|
if difference < 60 {
|
||||||
@ -400,6 +431,55 @@ public func stringForRelativeActivityTimestamp(strings: PresentationStrings, dat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func stringForStoryActivityTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, preciseTime: Bool = false, relativeTimestamp: Int32, relativeTo timestamp: Int32) -> String {
|
||||||
|
let difference = timestamp - relativeTimestamp
|
||||||
|
if difference < 60 {
|
||||||
|
return strings.Time_JustNow
|
||||||
|
} else if difference < 60 * 60 {
|
||||||
|
let minutes = difference / 60
|
||||||
|
return strings.Time_MinutesAgo(minutes)
|
||||||
|
} else {
|
||||||
|
var t: time_t = time_t(relativeTimestamp)
|
||||||
|
var timeinfo: tm = tm()
|
||||||
|
localtime_r(&t, &timeinfo)
|
||||||
|
|
||||||
|
var now: time_t = time_t(timestamp)
|
||||||
|
var timeinfoNow: tm = tm()
|
||||||
|
localtime_r(&now, &timeinfoNow)
|
||||||
|
|
||||||
|
if timeinfo.tm_year != timeinfoNow.tm_year {
|
||||||
|
return strings.Time_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string
|
||||||
|
}
|
||||||
|
|
||||||
|
let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
|
||||||
|
if dayDifference == 0 || dayDifference == -1 {
|
||||||
|
let day: RelativeTimestampFormatDay
|
||||||
|
if dayDifference == 0 {
|
||||||
|
let minutes = difference / (60 * 60)
|
||||||
|
return strings.Time_HoursAgo(minutes)
|
||||||
|
} else {
|
||||||
|
day = .yesterday
|
||||||
|
}
|
||||||
|
return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min).string
|
||||||
|
} else if preciseTime {
|
||||||
|
let yearDate: String
|
||||||
|
if timeinfo.tm_year == timeinfoNow.tm_year {
|
||||||
|
if timeinfo.tm_yday == timeinfoNow.tm_yday {
|
||||||
|
yearDate = strings.Weekday_Today
|
||||||
|
} else {
|
||||||
|
yearDate = strings.Date_ChatDateHeader(monthAtIndex(Int(timeinfo.tm_mon), strings: strings), "\(timeinfo.tm_mday)").string
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
yearDate = strings.Date_ChatDateHeaderYear(monthAtIndex(Int(timeinfo.tm_mon), strings: strings), "\(timeinfo.tm_mday)", "\(1900 + timeinfo.tm_year)").string
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Time_AtPreciseDate(yearDate, stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)).string
|
||||||
|
} else {
|
||||||
|
return strings.Time_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func stringAndActivityForUserPresence(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, presence: EnginePeer.Presence, relativeTo timestamp: Int32, expanded: Bool = false) -> (String, Bool) {
|
public func stringAndActivityForUserPresence(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, presence: EnginePeer.Presence, relativeTo timestamp: Int32, expanded: Bool = false) -> (String, Bool) {
|
||||||
switch presence.status {
|
switch presence.status {
|
||||||
case let .present(statusTimestamp):
|
case let .present(statusTimestamp):
|
||||||
|
@ -92,7 +92,7 @@ final class StoryAuthorInfoComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||||
var subtitle = stringForRelativeActivityTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, preciseTime: true, relativeTimestamp: component.timestamp, relativeTo: timestamp)
|
var subtitle = stringForStoryActivityTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, preciseTime: true, relativeTimestamp: component.timestamp, relativeTo: timestamp)
|
||||||
|
|
||||||
if component.isEdited {
|
if component.isEdited {
|
||||||
subtitle.append(" • ")
|
subtitle.append(" • ")
|
||||||
|
@ -368,17 +368,38 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let completionImpl: () -> Void = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if let chatListController = self.chatListController as? ChatListControllerImpl {
|
if let chatListController = self.chatListController as? ChatListControllerImpl {
|
||||||
chatListController.scrollToStories()
|
let _ = (chatListController.hasPendingStories
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> timeout(0.25, queue: .mainQueue(), alternate: .single(true))
|
||||||
|
|> deliverOnMainQueue).start(completed: { [weak chatListController] in
|
||||||
|
chatListController?.scrollToStories()
|
||||||
|
Queue.mainQueue().justDispatch {
|
||||||
|
commit({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Queue.mainQueue().justDispatch {
|
||||||
|
commit({})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let _ = self.chatListController as? ChatListControllerImpl {
|
||||||
switch mediaResult {
|
switch mediaResult {
|
||||||
case let .image(image, dimensions):
|
case let .image(image, dimensions):
|
||||||
if let imageData = compressImageToJPEG(image, quality: 0.7) {
|
if let imageData = compressImageToJPEG(image, quality: 0.7) {
|
||||||
let entities = generateChatInputTextEntities(caption)
|
let entities = generateChatInputTextEntities(caption)
|
||||||
Logger.shared.log("MediaEditor", "Calling uploadStory for image, randomId \(randomId)")
|
Logger.shared.log("MediaEditor", "Calling uploadStory for image, randomId \(randomId)")
|
||||||
self.context.engine.messages.uploadStory(media: .image(dimensions: dimensions, data: imageData, stickers: stickers), text: caption.string, entities: entities, pin: privacy.pin, privacy: privacy.privacy, isForwardingDisabled: privacy.isForwardingDisabled, period: privacy.timeout, randomId: randomId)
|
self.context.engine.messages.uploadStory(media: .image(dimensions: dimensions, data: imageData, stickers: stickers), text: caption.string, entities: entities, pin: privacy.pin, privacy: privacy.privacy, isForwardingDisabled: privacy.isForwardingDisabled, period: privacy.timeout, randomId: randomId)
|
||||||
Queue.mainQueue().justDispatch {
|
|
||||||
commit({})
|
completionImpl()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case let .video(content, firstFrameImage, values, duration, dimensions):
|
case let .video(content, firstFrameImage, values, duration, dimensions):
|
||||||
let adjustments: VideoMediaResourceAdjustments
|
let adjustments: VideoMediaResourceAdjustments
|
||||||
@ -408,9 +429,8 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
|||||||
Logger.shared.log("MediaEditor", "Calling uploadStory for video, randomId \(randomId)")
|
Logger.shared.log("MediaEditor", "Calling uploadStory for video, randomId \(randomId)")
|
||||||
let entities = generateChatInputTextEntities(caption)
|
let entities = generateChatInputTextEntities(caption)
|
||||||
self.context.engine.messages.uploadStory(media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameFile: firstFrameFile, stickers: stickers), text: caption.string, entities: entities, pin: privacy.pin, privacy: privacy.privacy, isForwardingDisabled: privacy.isForwardingDisabled, period: privacy.timeout, randomId: randomId)
|
self.context.engine.messages.uploadStory(media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameFile: firstFrameFile, stickers: stickers), text: caption.string, entities: entities, pin: privacy.pin, privacy: privacy.privacy, isForwardingDisabled: privacy.isForwardingDisabled, period: privacy.timeout, randomId: randomId)
|
||||||
Queue.mainQueue().justDispatch {
|
|
||||||
commit({})
|
completionImpl()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user