diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 3477df456a..6f95404192 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1363,6 +1363,14 @@ rpl::producer<> Session::savedGifsUpdated() const { return _savedGifsUpdated.events(); } +void Session::notifyPinnedDialogsOrderUpdated() { + _pinnedDialogsOrderUpdated.fire({}); +} + +rpl::producer<> Session::pinnedDialogsOrderUpdated() const { + return _pinnedDialogsOrderUpdated.events(); +} + void Session::userIsContactUpdated(not_null user) { const auto i = _contactViews.find(peerToUser(user->id)); if (i != _contactViews.end()) { @@ -1422,6 +1430,7 @@ void Session::setPinnedFromDialog(const Dialogs::Key &key, bool pinned) { void Session::applyPinnedChats( Data::Folder *folder, const QVector &list) { + notifyPinnedDialogsOrderUpdated() for (const auto &peer : list) { peer.match([&](const MTPDdialogPeer &data) { const auto history = this->history(peerFromMTP(data.vpeer)); @@ -1481,6 +1490,7 @@ void Session::applyDialog( void Session::applyDialog( Data::Folder *requestFolder, const MTPDdialogFolder &data) { + notifyPinnedDialogsOrderUpdated() if (requestFolder) { LOG(("API Error: requestFolder != nullptr for dialogFolder.")); } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 43ef82839e..805a22b397 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -228,6 +228,8 @@ public: [[nodiscard]] rpl::producer<> stickersUpdated() const; void notifySavedGifsUpdated(); [[nodiscard]] rpl::producer<> savedGifsUpdated() const; + void notifyPinnedDialogsOrderUpdated(); + [[nodiscard]] rpl::producer<> pinnedDialogsOrderUpdated() const; bool stickersUpdateNeeded(crl::time now) const { return stickersUpdateNeeded(_lastStickersUpdate, now); @@ -830,6 +832,7 @@ private: rpl::event_stream<> _stickersUpdated; rpl::event_stream<> _savedGifsUpdated; + rpl::event_stream<> _pinnedDialogsOrderUpdated; crl::time _lastStickersUpdate = 0; crl::time _lastRecentStickersUpdate = 0; crl::time _lastFavedStickersUpdate = 0; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index a4f010e23c..e10af3e813 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/player/media_player_instance.h" #include "media/audio/media_audio.h" #include "platform/mac/touchbar.h" +#include "data/data_session.h" @interface MainWindowObserver : NSObject { } @@ -395,6 +396,20 @@ MainWindow::MainWindow() } }); + subscribe(Core::App().authSessionChanged(), [this] { + if (AuthSession::Exists()) { + + Auth().data().pinnedDialogsOrderUpdated( + ) | rpl::start_with_next([this] { + if (auto view = reinterpret_cast(winId())) { + // Create TouchBar. + [NSApplication sharedApplication].automaticCustomizeTouchBarMenuItemEnabled = YES; + _private->_touchBar = [[TouchBar alloc] init:view]; + } + }, lifetime()); + } + }); + subscribe(Media::Player::instance()->updatedNotifier(), [=](const Media::Player::TrackState &state) { [_private->_touchBar handlePropertyChange:state]; @@ -429,9 +444,6 @@ void MainWindow::initHook() { if (auto window = [view window]) { _private->setNativeWindow(window, view); } - // Create TouchBar. - [NSApplication sharedApplication].automaticCustomizeTouchBarMenuItemEnabled = YES; - _private->_touchBar = [[TouchBar alloc] init:view]; } } diff --git a/Telegram/SourceFiles/platform/mac/touchbar.h b/Telegram/SourceFiles/platform/mac/touchbar.h index 4a05cdf003..a230f05557 100644 --- a/Telegram/SourceFiles/platform/mac/touchbar.h +++ b/Telegram/SourceFiles/platform/mac/touchbar.h @@ -23,6 +23,13 @@ static NSString * _Nullable BASE_ID = @"telegram.touchbar"; static NSTouchBarCustomizationIdentifier _Nullable customID = @"telegram.touchbar"; static NSTouchBarCustomizationIdentifier _Nullable customIDMain = @"telegram.touchbarMain"; static NSTouchBarItemIdentifier _Nullable savedMessages = [NSString stringWithFormat:@"%@.savedMessages", customIDMain]; + +static NSTouchBarItemIdentifier _Nullable pinnedDialog1 = [NSString stringWithFormat:@"%@.pinnedDialog1", customIDMain]; +static NSTouchBarItemIdentifier _Nullable pinnedDialog2 = [NSString stringWithFormat:@"%@.pinnedDialog2", customIDMain]; +static NSTouchBarItemIdentifier _Nullable pinnedDialog3 = [NSString stringWithFormat:@"%@.pinnedDialog3", customIDMain]; +static NSTouchBarItemIdentifier _Nullable pinnedDialog4 = [NSString stringWithFormat:@"%@.pinnedDialog4", customIDMain]; +static NSTouchBarItemIdentifier _Nullable pinnedDialog5 = [NSString stringWithFormat:@"%@.pinnedDialog5", customIDMain]; + static NSTouchBarItemIdentifier _Nullable seekBar = [NSString stringWithFormat:@"%@.seekbar", BASE_ID]; static NSTouchBarItemIdentifier _Nullable play = [NSString stringWithFormat:@"%@.play", BASE_ID]; static NSTouchBarItemIdentifier _Nullable nextItem = [NSString stringWithFormat:@"%@.nextItem", BASE_ID]; diff --git a/Telegram/SourceFiles/platform/mac/touchbar.mm b/Telegram/SourceFiles/platform/mac/touchbar.mm index d6c3d6af55..22929e3b21 100644 --- a/Telegram/SourceFiles/platform/mac/touchbar.mm +++ b/Telegram/SourceFiles/platform/mac/touchbar.mm @@ -24,6 +24,9 @@ #include "lang/lang_keys.h" #include "base/timer.h" #include "styles/style_window.h" +#include "auth_session.h" +#include "data/data_session.h" +#include "history/history.h" namespace { constexpr auto kSavedMessages = 0x001; @@ -38,12 +41,96 @@ constexpr auto kMs = 1000; constexpr auto kSongType = AudioMsgId::Type::Song; } // namespace +NSImage *qt_mac_create_nsimage(const QPixmap &pm); + +@interface PinnedDialogButton : NSCustomTouchBarItem { +} + +@property(nonatomic, assign) int number; +@property(nonatomic, assign) bool waiting; +@property(nonatomic, assign) PeerData * peer; + +- (id) init:(int)num; +- (NSImage *) getPinImage; +- (void)buttonActionPin:(NSButton *)sender; +- (void)updatePeerData; + +@end // @interface PinnedDialogButton + +@implementation PinnedDialogButton : NSCustomTouchBarItem + +- (id) init:(int)num { + NSString *identifier = [NSString stringWithFormat:@"%@.pinnedDialog%d", customIDMain, num]; + self = [super initWithIdentifier:identifier]; + if (!self) { + return nil; + } + self.number = num; + self.waiting = true; + [self updatePeerData]; + + NSButton *button = [NSButton buttonWithImage:[self getPinImage] target:self action:@selector(buttonActionPin:)]; + [button setBordered:NO]; + [button sizeToFit]; + [button setHidden:(num > Auth().data().pinnedDialogsOrder().size())]; + self.view = button; + self.customizationLabel = [NSString stringWithFormat:@"Pinned Dialog %d", num]; + + base::ObservableViewer( + Auth().downloaderTaskFinished() + ) | rpl::start_with_next([self] { + if (self.waiting) { + NSButton *button = self.view; + button.image = [self getPinImage]; + } + }, Auth().lifetime()); + + return self; +} + +- (void)updatePeerData { + const auto &order = Auth().data().pinnedDialogsOrder(); + if (self.number > order.size()) { + self.peer = nil; + return; + } + // Order is reversed. + const auto pinned = order.at(order.size() - self.number); + if (const auto history = pinned.history()) { + self.peer = history->peer; + } +} + +- (void)buttonActionPin:(NSButton *)sender { + Core::Sandbox::Instance().customEnterFromEventLoop([=] { + App::main()->choosePeer(self.peer->id, ShowAtUnreadMsgId); + }); +} + + +- (NSImage *) getPinImage { + if (!self.peer) { + return nil; + } + self.waiting = !self.peer->userpicLoaded(); + auto pixmap = self.peer->genUserpic(20); + pixmap.setDevicePixelRatio(cRetinaFactor()); + return static_cast(qt_mac_create_nsimage(pixmap)); +} + + +@end + + +@interface TouchBar() +@end // @interface TouchBar + @interface TouchBar() @end @implementation TouchBar -- (id)init:(NSView *)view { +- (id)init:(NSView *)view{ self = [super init]; if (self) { self.view = view; @@ -52,7 +139,27 @@ constexpr auto kSongType = AudioMsgId::Type::Song; @"type": @"button", @"name": @"Saved Messages", @"cmd": [NSNumber numberWithInt:kSavedMessages], - @"image": [NSImage imageNamed:NSImageNameTouchBarBookmarksTemplate], + @"image": [NSImage imageNamed:NSImageNameTouchBarBookmarksTemplate], + }], + pinnedDialog1: [NSMutableDictionary dictionaryWithDictionary:@{ + @"type": @"pinned", + @"num": @1, + }], + pinnedDialog2: [NSMutableDictionary dictionaryWithDictionary:@{ + @"type": @"pinned", + @"num": @2, + }], + pinnedDialog3: [NSMutableDictionary dictionaryWithDictionary:@{ + @"type": @"pinned", + @"num": @3, + }], + pinnedDialog4: [NSMutableDictionary dictionaryWithDictionary:@{ + @"type": @"pinned", + @"num": @4, + }], + pinnedDialog5: [NSMutableDictionary dictionaryWithDictionary:@{ + @"type": @"pinned", + @"num": @5, }], seekBar: [NSMutableDictionary dictionaryWithDictionary:@{ @"type": @"slider", @@ -89,8 +196,8 @@ constexpr auto kSongType = AudioMsgId::Type::Song; }] }; } - [self createTouchBar]; - [self setTouchBar:TouchBarType::Main]; + [self createTouchBar]; + [self setTouchBar:TouchBarType::Main]; return self; } @@ -100,20 +207,21 @@ constexpr auto kSongType = AudioMsgId::Type::Song; _touchBarMain.delegate = self; _touchBarMain.customizationIdentifier = customIDMain; - _touchBarMain.defaultItemIdentifiers = @[savedMessages]; + _touchBarMain.defaultItemIdentifiers = @[savedMessages, pinnedDialog1, pinnedDialog2, pinnedDialog3, pinnedDialog4, pinnedDialog5]; _touchBarMain.customizationAllowedItemIdentifiers = @[savedMessages]; - _touchBarAudioPlayer = [[NSTouchBar alloc] init]; - _touchBarAudioPlayer.delegate = self; + _touchBarAudioPlayer = [[NSTouchBar alloc] init]; + _touchBarAudioPlayer.delegate = self; - _touchBarAudioPlayer.customizationIdentifier = customID; - _touchBarAudioPlayer.defaultItemIdentifiers = @[play, previousItem, nextItem, seekBar, closePlayer]; - _touchBarAudioPlayer.customizationAllowedItemIdentifiers = @[play, previousItem, - nextItem, currentPosition, seekBar, closePlayer]; + _touchBarAudioPlayer.customizationIdentifier = customID; + _touchBarAudioPlayer.defaultItemIdentifiers = @[play, previousItem, nextItem, seekBar, closePlayer]; + _touchBarAudioPlayer.customizationAllowedItemIdentifiers = @[play, previousItem, + nextItem, currentPosition, seekBar, closePlayer]; } - (nullable NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { + if ([self.touchbarItems[identifier][@"type"] isEqualToString:@"slider"]) { NSSliderTouchBarItem *item = [[NSSliderTouchBarItem alloc] initWithIdentifier:identifier]; item.slider.minValue = 0.0f; @@ -139,6 +247,13 @@ constexpr auto kSongType = AudioMsgId::Type::Song; item.customizationLabel = self.touchbarItems[identifier][@"name"]; [self.touchbarItems[identifier] setObject:text forKey:@"view"]; return item; + } else if ([self.touchbarItems[identifier][@"type"] isEqualToString:@"pinned"]) { + const auto number = [self.touchbarItems[identifier][@"num"] intValue]; + PinnedDialogButton *item = [[PinnedDialogButton alloc] init:number]; + NSImage *image = self.touchbarItems[identifier][@"image"]; + + [self.touchbarItems[identifier] setObject:item.view forKey:@"view"]; + return item; } return nil;