blob: 48d50cf0b59eedd1598a7a72cf501afdb95c4c0f [file] [log] [blame]
Alexandre Lision8521baa2015-03-13 11:08:00 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision8521baa2015-03-13 11:08:00 -04003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lision8521baa2015-03-13 11:08:00 -040018 */
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050019#import "GeneralPrefsVC.h"
20
Alexandre Lision261f1b92016-04-04 12:35:34 -040021#import <Quartz/Quartz.h>
22
23//Qt
24#import <QSize>
25#import <QtMacExtras/qmacfunctions.h>
26#import <QPixmap>
27
28//LRC
Alexandre Lisione4041492015-03-20 18:20:43 -040029#import <categorizedhistorymodel.h>
Alexandre Lision261f1b92016-04-04 12:35:34 -040030#import <profilemodel.h>
31#import <profile.h>
32#import <person.h>
33#import <globalinstances.h>
Kateryna Kostiuk9aef8492017-06-22 16:58:36 -040034#import <media/recordingmodel.h>
Alexandre Lisione4041492015-03-20 18:20:43 -040035
Alexandre Lision3d4143a2015-06-10 14:27:49 -040036#if ENABLE_SPARKLE
37#import <Sparkle/Sparkle.h>
38#endif
39
Alexandre Lisionc65310c2015-04-23 16:44:23 -040040#import "Constants.h"
Alexandre Lision261f1b92016-04-04 12:35:34 -040041#import "views/NSImage+Extensions.h"
42#import "delegates/ImageManipulationDelegate.h"
Alexandre Lisionc65310c2015-04-23 16:44:23 -040043
Alexandre Lision261f1b92016-04-04 12:35:34 -040044@interface GeneralPrefsVC () {
45 __unsafe_unretained IBOutlet NSTextField* historyChangedLabel;
46 __unsafe_unretained IBOutlet NSButton* startUpButton;
47 __unsafe_unretained IBOutlet NSButton* toggleAutomaticUpdateCheck;
48 __unsafe_unretained IBOutlet NSPopUpButton* checkIntervalPopUp;
49 __unsafe_unretained IBOutlet NSView* sparkleContainer;
50 __unsafe_unretained IBOutlet NSTextField* historyTextField;
51 __unsafe_unretained IBOutlet NSStepper* historyStepper;
52 __unsafe_unretained IBOutlet NSButton* historySwitch;
53 __unsafe_unretained IBOutlet NSButton* photoView;
54 __unsafe_unretained IBOutlet NSTextField* profileNameField;
55}
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050056@end
57
Alexandre Lision4de68ce2015-04-24 18:22:49 -040058@implementation GeneralPrefsVC
Alexandre Lisione4041492015-03-20 18:20:43 -040059
60- (void)loadView
61{
62 [super loadView];
Alexandre Lisionc65310c2015-04-23 16:44:23 -040063 [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:Preferences::HistoryLimit options:NSKeyValueObservingOptionNew context:NULL];
Alexandre Lision4de68ce2015-04-24 18:22:49 -040064
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +020065 [startUpButton setState:[self isLaunchAtStartup]];
66
Alexandre Lisionaa03df42016-01-26 09:39:25 -050067 int historyLimit = CategorizedHistoryModel::instance().historyLimit();
68 [historyTextField setStringValue:[NSString stringWithFormat:@"%d", historyLimit]];
69 [historyStepper setIntValue:historyLimit];
70
71 BOOL limited = CategorizedHistoryModel::instance().isHistoryLimited();
72 [historySwitch setState:limited];
73 [historyStepper setEnabled:limited];
74 [historyTextField setEnabled:limited];
Alexandre Lision3d4143a2015-06-10 14:27:49 -040075#if ENABLE_SPARKLE
76 [sparkleContainer setHidden:NO];
77 SUUpdater *updater = [SUUpdater sharedUpdater];
78 [toggleAutomaticUpdateCheck bind:@"value" toObject:updater withKeyPath:@"automaticallyChecksForUpdates" options:nil];
79
80 [checkIntervalPopUp bind:@"enabled" toObject:updater withKeyPath:@"automaticallyChecksForUpdates" options:nil];
81 [checkIntervalPopUp bind:@"selectedTag" toObject:updater withKeyPath:@"updateCheckInterval" options:nil];
82#else
83 [sparkleContainer setHidden:YES];
84#endif
85
Alexandre Lision261f1b92016-04-04 12:35:34 -040086 [photoView setWantsLayer: YES];
87 photoView.layer.cornerRadius = photoView.frame.size.width / 2;
88 photoView.layer.masksToBounds = YES;
89
90 if (auto pro = ProfileModel::instance().selectedProfile()) {
91 auto photo = GlobalInstances::pixmapManipulator().contactPhoto(pro->person(), {140,140});
92 [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
93 [profileNameField setStringValue:pro->person()->formattedName().toNSString()];
94 }
95
Alexandre Lisione4041492015-03-20 18:20:43 -040096}
97
Alexandre Lision81c97212015-06-17 15:51:53 -040098- (void) dealloc
99{
100 [[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:Preferences::HistoryLimit];
Alexandre Lision81c97212015-06-17 15:51:53 -0400101}
102
Alexandre Lisione4041492015-03-20 18:20:43 -0400103- (IBAction)clearHistory:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400104 CategorizedHistoryModel::instance().clearAllCollections();
Kateryna Kostiuk9aef8492017-06-22 16:58:36 -0400105 Media::RecordingModel::instance().clearAllCollections();
Alexandre Lisione4041492015-03-20 18:20:43 -0400106 [historyChangedLabel setHidden:NO];
107}
108
Alexandre Lision261f1b92016-04-04 12:35:34 -0400109- (IBAction)toggleHistory:(NSButton*)sender {
Alexandre Lisionaa03df42016-01-26 09:39:25 -0500110 CategorizedHistoryModel::instance().setHistoryLimited([sender state]);
111 int historyLimit = CategorizedHistoryModel::instance().historyLimit();
112 [historyTextField setStringValue:[NSString stringWithFormat:@"%d", historyLimit]];
113 [historyStepper setIntValue:historyLimit];
114 [historyChangedLabel setHidden:NO];
115 [historyStepper setEnabled:[sender state]];
116 [historyTextField setEnabled:[sender state]];
117}
118
Alexandre Lisione4041492015-03-20 18:20:43 -0400119// KVO handler
120-(void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject
121 change:(NSDictionary *)aChange context:(void *)aContext
122{
Alexandre Lisionaa03df42016-01-26 09:39:25 -0500123 if ([aKeyPath isEqualToString:Preferences::HistoryLimit]) {
124 CategorizedHistoryModel::instance().setHistoryLimit([[aChange objectForKey: NSKeyValueChangeNewKey] integerValue]);
Alexandre Lision4de68ce2015-04-24 18:22:49 -0400125 [historyChangedLabel setHidden:NO];
Alexandre Lision4de68ce2015-04-24 18:22:49 -0400126 }
Alexandre Lisione4041492015-03-20 18:20:43 -0400127}
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500128
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200129#pragma mark - Startup API
130
131// MIT license by Brian Dunagan
132- (BOOL)isLaunchAtStartup {
133 // See if the app is currently in LoginItems.
134 LSSharedFileListItemRef itemRef = [self itemRefInLoginItems];
135 // Store away that boolean.
136 BOOL isInList = itemRef != nil;
137 // Release the reference if it exists.
138 if (itemRef != nil) CFRelease(itemRef);
139
140 return isInList;
141}
142
143- (IBAction)toggleLaunchAtStartup:(id)sender {
144 // Toggle the state.
145 BOOL shouldBeToggled = ![self isLaunchAtStartup];
146 // Get the LoginItems list.
147 LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
148 if (loginItemsRef == nil) return;
149 if (shouldBeToggled) {
150 // Add the app to the LoginItems list.
Alexandre Lision81c97212015-06-17 15:51:53 -0400151 CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200152 LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL);
153 if (itemRef) CFRelease(itemRef);
154 }
155 else {
156 // Remove the app from the LoginItems list.
157 LSSharedFileListItemRef itemRef = [self itemRefInLoginItems];
158 LSSharedFileListItemRemove(loginItemsRef,itemRef);
159 if (itemRef != nil) CFRelease(itemRef);
160 }
161 CFRelease(loginItemsRef);
162}
163
164- (LSSharedFileListItemRef)itemRefInLoginItems {
165 LSSharedFileListItemRef itemRef = nil;
Alexandre Lision81c97212015-06-17 15:51:53 -0400166 CFURLRef itemUrl = nil;
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200167
168 // Get the app's URL.
Alexandre Lision81c97212015-06-17 15:51:53 -0400169 auto appUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200170 // Get the LoginItems list.
171 LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
172 if (loginItemsRef == nil) return nil;
173 // Iterate over the LoginItems.
Alexandre Lision81c97212015-06-17 15:51:53 -0400174 NSArray *loginItems = (__bridge_transfer NSArray *)LSSharedFileListCopySnapshot(loginItemsRef, nil);
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200175 for (int currentIndex = 0; currentIndex < [loginItems count]; currentIndex++) {
176 // Get the current LoginItem and resolve its URL.
Alexandre Lision81c97212015-06-17 15:51:53 -0400177 LSSharedFileListItemRef currentItemRef = (__bridge LSSharedFileListItemRef)[loginItems objectAtIndex:currentIndex];
178 if (LSSharedFileListItemResolve(currentItemRef, 0, &itemUrl, NULL) == noErr) {
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200179 // Compare the URLs for the current LoginItem and the app.
Alexandre Lision81c97212015-06-17 15:51:53 -0400180 if ([(__bridge NSURL *)itemUrl isEqual:appUrl]) {
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200181 // Save the LoginItem reference.
182 itemRef = currentItemRef;
183 }
184 }
185 }
186 // Retain the LoginItem reference.
187 if (itemRef != nil) CFRetain(itemRef);
188 // Release the LoginItems lists.
Alexandre Lision1ad5a2f2015-05-27 14:21:45 +0200189 CFRelease(loginItemsRef);
190
191 return itemRef;
192}
193
Alexandre Lision261f1b92016-04-04 12:35:34 -0400194#pragma mark - Profile Photo edition
195
196- (IBAction) editPhoto:(id)sender {
197 auto pictureTaker = [IKPictureTaker pictureTaker];
198 [pictureTaker beginPictureTakerSheetForWindow:self.view.window
199 withDelegate:self
200 didEndSelector:@selector(pictureTakerDidEnd:returnCode:contextInfo:)
201 contextInfo:nil];
202}
203
204- (void) pictureTakerDidEnd:(IKPictureTaker *) picker
205 returnCode:(NSInteger) code
206 contextInfo:(void*) contextInfo
207{
208 if (auto outputImage = [picker outputImage]) {
209 [photoView setImage:outputImage];
210 } else
211 [photoView setImage:[NSImage imageNamed:@"default_user_icon"]];
212 if (auto pro = ProfileModel::instance().selectedProfile()) {
213 QPixmap p;
214 auto smallImg = [NSImage imageResize:[photoView image] newSize:{100,100}];
215 if (p.loadFromData(QByteArray::fromNSData([smallImg TIFFRepresentation]))) {
216 pro->person()->setPhoto(QVariant(p));
217 }
218 pro->save();
219 }
220}
221
222#pragma mark - NSTextFieldDelegate methods
223
224-(void)controlTextDidChange:(NSNotification *)notif
225{
226 if (auto pro = ProfileModel::instance().selectedProfile()) {
227 pro->person()->setFormattedName(profileNameField.stringValue.UTF8String);
228 pro->save();
229 }
230}
231
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500232@end