Feature: Replaced Crashlytics with Sentry

Crash logging is now handled by the Sentry service.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-02-26 01:11:55 -08:00
parent 0c8f072deb
commit fd774d17a5
20 changed files with 232 additions and 304 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@ xcuserdata
# User-specific xcconfig files # User-specific xcconfig files
Xcode-config/DEVELOPMENT_TEAM.xcconfig Xcode-config/DEVELOPMENT_TEAM.xcconfig
Xcode-config/SENTRY_SETTINGS.xcconfig
# Plist derived from template at build time # Plist derived from template at build time
/Info.plist /Info.plist

View file

@ -33,7 +33,9 @@
#import "PreferencesController.h" #import "PreferencesController.h"
@import Firebase; #import "FeedbackController.h"
@import Sentry;
void *kAppControllerContext = &kAppControllerContext; void *kAppControllerContext = &kAppControllerContext;
@ -184,18 +186,13 @@ static AppController *kAppController = nil;
return [key isEqualToString:@"currentEntry"]; return [key isEqualToString:@"currentEntry"];
} }
static BOOL consentLastEnabled = NO;
- (void)awakeFromNib { - (void)awakeFromNib {
#if DEBUG [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"sentryConsented": @(NO),
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @(NO) }]; @"sentryAskedConsent": @(NO) }];
#else
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @(YES) }]; [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.sentryConsented" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kAppControllerContext];
#endif
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"crashlyticsConsented": @(NO),
@"crashlyticsAskedConsent": @(NO) }];
[FIRApp configure];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.crashlyticsConsented" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kAppControllerContext];
#ifdef DEBUG #ifdef DEBUG
// Prevent updates automatically in debug builds // Prevent updates automatically in debug builds
@ -347,10 +344,45 @@ static AppController *kAppController = nil;
return; return;
} }
if([keyPath isEqualToString:@"values.crashlyticsConsented"]) { if([keyPath isEqualToString:@"values.sentryConsented"]) {
BOOL enabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"crashlyticsConsented"]; BOOL enabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"sentryConsented"];
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:enabled]; if(enabled != consentLastEnabled) {
[FIRAnalytics setAnalyticsCollectionEnabled:enabled]; if(enabled) {
[SentrySDK startWithConfigureOptions:^(SentryOptions *options) {
options.dsn = @"https://b5eda1c2390eb965a74dd735413b6392@cog-analytics.losno.co/3";
options.debug = YES; // Enabled debug when first installing is always helpful
// Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
// We recommend adjusting this value in production.
options.tracesSampleRate = @1.0;
// Adds IP for users.
// For more information, visit: https://docs.sentry.io/platforms/apple/data-management/data-collected/
options.sendDefaultPii = YES;
// And now to set up user feedback prompting
options.onCrashedLastRun = ^void(SentryEvent * _Nonnull event) {
// capture user feedback
FeedbackController *fbcon = [[FeedbackController alloc] init];
[fbcon performSelectorOnMainThread:@selector(showWindow:) withObject:nil waitUntilDone:YES];
if([fbcon waitForCompletion]) {
SentryUserFeedback *userFeedback = [[SentryUserFeedback alloc] initWithEventId:[event eventId]];
userFeedback.comments = [fbcon comments];
userFeedback.email = [fbcon email];
userFeedback.name = [fbcon name];
[SentrySDK captureUserFeedback:userFeedback];
}
};
}];
} else {
if([SentrySDK isEnabled]) {
[SentrySDK close];
}
}
consentLastEnabled = enabled;
}
} else if([keyPath isEqualToString:@"playlistController.currentEntry"]) { } else if([keyPath isEqualToString:@"playlistController.currentEntry"]) {
PlaylistEntry *entry = playlistController.currentEntry; PlaylistEntry *entry = playlistController.currentEntry;
NSString *appTitle = NSLocalizedString(@"CogTitle", @""); NSString *appTitle = NSLocalizedString(@"CogTitle", @"");

View file

@ -19,7 +19,7 @@
#import "Logging.h" #import "Logging.h"
@import Firebase; //@import Sentry;
extern BOOL kAppControllerShuttingDown; extern BOOL kAppControllerShuttingDown;
@ -284,11 +284,11 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
if(!pe.url) { if(!pe.url) {
pe.error = YES; pe.error = YES;
pe.errorMessage = NSLocalizedStringFromTableInBundle(@"ErrorMessageBadFile", nil, [NSBundle bundleForClass:[self class]], @""); pe.errorMessage = NSLocalizedStringFromTableInBundle(@"ErrorMessageBadFile", nil, [NSBundle bundleForClass:[self class]], @"");
[[FIRCrashlytics crashlytics] log:@"Attempting to play bad file."]; //[[FIRCrashlytics crashlytics] log:@"Attempting to play bad file."];
return; return;
} }
[[FIRCrashlytics crashlytics] logWithFormat:@"Playing track: %@", pe.url]; //[[FIRCrashlytics crashlytics] logWithFormat:@"Playing track: %@", pe.url];
DLog(@"PLAYLIST CONTROLLER: %@", [playlistController class]); DLog(@"PLAYLIST CONTROLLER: %@", [playlistController class]);
[playlistController setCurrentEntry:pe]; [playlistController setCurrentEntry:pe];
@ -767,15 +767,15 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
} }
if(pe && pe.url) { if(pe && pe.url) {
[[FIRCrashlytics crashlytics] logWithFormat:@"Beginning decoding track: %@", pe.url]; //[[FIRCrashlytics crashlytics] logWithFormat:@"Beginning decoding track: %@", pe.url];
[player setNextStream:pe.url withUserInfo:pe withRGInfo:makeRGInfo(pe)]; [player setNextStream:pe.url withUserInfo:pe withRGInfo:makeRGInfo(pe)];
} else if(pe) { } else if(pe) {
[[FIRCrashlytics crashlytics] log:@"Invalid playlist entry reached."]; //[[FIRCrashlytics crashlytics] log:@"Invalid playlist entry reached."];
[player setNextStream:nil]; [player setNextStream:nil];
pe.error = YES; pe.error = YES;
pe.errorMessage = NSLocalizedStringFromTableInBundle(@"ErrorMessageBadFile", nil, [NSBundle bundleForClass:[self class]], @""); pe.errorMessage = NSLocalizedStringFromTableInBundle(@"ErrorMessageBadFile", nil, [NSBundle bundleForClass:[self class]], @"");
} else { } else {
[[FIRCrashlytics crashlytics] log:@"End of playlist reached."]; //[[FIRCrashlytics crashlytics] log:@"End of playlist reached."];
[player setNextStream:nil]; [player setNextStream:nil];
} }
} }
@ -786,7 +786,7 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
// Delay the action until this function has returned to the audio thread // Delay the action until this function has returned to the audio thread
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
if(pe) { if(pe) {
[[FIRCrashlytics crashlytics] logWithFormat:@"Updating UI with track: %@", pe.url]; //[[FIRCrashlytics crashlytics] logWithFormat:@"Updating UI with track: %@", pe.url];
} }
[self->playlistController setCurrentEntry:pe]; [self->playlistController setCurrentEntry:pe];
@ -817,7 +817,7 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
} }
if(status == CogStatusStopped) { if(status == CogStatusStopped) {
[[FIRCrashlytics crashlytics] log:@"Stopped."]; //[[FIRCrashlytics crashlytics] log:@"Stopped."];
[self setPosition:0]; [self setPosition:0];
[self setSeekable:NO]; // the player stopped, disable the slider [self setSeekable:NO]; // the player stopped, disable the slider
@ -825,11 +825,11 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidStopNotificiation object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidStopNotificiation object:nil];
} else // paused } else // paused
{ {
[[FIRCrashlytics crashlytics] log:@"Paused."]; //[[FIRCrashlytics crashlytics] log:@"Paused."];
[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidPauseNotificiation object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidPauseNotificiation object:nil];
} }
} else if(status == CogStatusPlaying) { } else if(status == CogStatusPlaying) {
[[FIRCrashlytics crashlytics] log:@"Started playing."]; //[[FIRCrashlytics crashlytics] log:@"Started playing."];
if(!positionTimer) { if(!positionTimer) {
positionTimer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(updatePosition:) userInfo:nil repeats:YES]; positionTimer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(updatePosition:) userInfo:nil repeats:YES];
@ -865,7 +865,7 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
- (void)audioPlayer:(AudioPlayer *)player didStopNaturally:(id)userInfo { - (void)audioPlayer:(AudioPlayer *)player didStopNaturally:(id)userInfo {
if([[NSUserDefaults standardUserDefaults] boolForKey:@"quitOnNaturalStop"]) { if([[NSUserDefaults standardUserDefaults] boolForKey:@"quitOnNaturalStop"]) {
[[FIRCrashlytics crashlytics] log:@"Terminating due to natural stop."]; //[[FIRCrashlytics crashlytics] log:@"Terminating due to natural stop."];
[NSApp terminate:nil]; [NSApp terminate:nil];
} }
} }
@ -880,7 +880,7 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
- (void)audioPlayer:(AudioPlayer *)player restartPlaybackAtCurrentPosition:(id)userInfo { - (void)audioPlayer:(AudioPlayer *)player restartPlaybackAtCurrentPosition:(id)userInfo {
PlaylistEntry *pe = [playlistController currentEntry]; PlaylistEntry *pe = [playlistController currentEntry];
BOOL paused = playbackStatus == CogStatusPaused; BOOL paused = playbackStatus == CogStatusPaused;
[[FIRCrashlytics crashlytics] logWithFormat:@"Restarting playback of track: %@", pe.url]; //[[FIRCrashlytics crashlytics] logWithFormat:@"Restarting playback of track: %@", pe.url];
[player performSelectorOnMainThread:@selector(playBG:withUserInfo:withRGInfo:startPaused:andSeekTo:) withObjects:pe.url, pe, makeRGInfo(pe), @(paused), @(pe.seekable ? pe.currentPosition : 0.0), nil]; [player performSelectorOnMainThread:@selector(playBG:withUserInfo:withRGInfo:startPaused:andSeekTo:) withObjects:pe.url, pe, makeRGInfo(pe), @(paused), @(pe.seekable ? pe.currentPosition : 0.0), nil];
} }

View file

@ -389,8 +389,6 @@ static NSString *xmlEscapeString(NSString * string) {
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\ <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
<plist version=\"1.0\">\n\ <plist version=\"1.0\">\n\
<dict>\n\ <dict>\n\
\t<key>FirebaseCrashlyticsCollectionEnabled</key>\n\
\t<false/>\n\
\t<key>SUEnableInstallerLauncherService</key>\n\ \t<key>SUEnableInstallerLauncherService</key>\n\
\t<true/>\n\ \t<true/>\n\
\t<key>CFBundleDevelopmentRegion</key>\n\ \t<key>CFBundleDevelopmentRegion</key>\n\

View file

@ -1,23 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22113.1" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22113.1"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>
<customObject id="-2" userLabel="File's Owner" customClass="FeedbackController"> <customObject id="-2" userLabel="File's Owner" customClass="FeedbackController">
<connections> <connections>
<outlet property="fromView" destination="5" id="37"/> <outlet property="emailView" destination="10" id="X4O-Qx-zUq"/>
<outlet property="messageView" destination="15" id="38"/> <outlet property="messageView" destination="15" id="gwe-Bb-ZEz"/>
<outlet property="sendingIndicator" destination="12" id="39"/> <outlet property="nameView" destination="5" id="9Uz-Hh-EVf"/>
<outlet property="subjectView" destination="10" id="36"/>
<outlet property="window" destination="1" id="42"/> <outlet property="window" destination="1" id="42"/>
</connections> </connections>
</customObject> </customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Send Feedback" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="1" userLabel="FeedbackWindow"> <window title="Send Crash Feedback" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="1" userLabel="FeedbackWindow">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="168" y="357" width="480" height="376"/> <rect key="contentRect" x="168" y="357" width="480" height="376"/>
@ -27,7 +26,37 @@
<rect key="frame" x="0.0" y="0.0" width="480" height="376"/> <rect key="frame" x="0.0" y="0.0" width="480" height="376"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="10"> <textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8" userLabel="Name:">
<rect key="frame" x="17" y="339" width="58" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Name:" id="18" userLabel="Name:">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5" userLabel="Name Field">
<rect key="frame" x="80" y="337" width="356" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="21">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="nextKeyView" destination="10" id="CNG-sG-ab3"/>
</connections>
</textField>
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4">
<rect key="frame" x="17" y="297" width="58" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Email:" id="22">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="10" userLabel="Email Field">
<rect key="frame" x="80" y="295" width="356" height="22"/> <rect key="frame" x="80" y="295" width="356" height="22"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="16"> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="16">
@ -36,22 +65,13 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
<connections> <connections>
<outlet property="nextKeyView" destination="15" id="30"/> <outlet property="nextKeyView" destination="15" id="Xi7-6Y-bG1"/>
</connections> </connections>
</textField> </textField>
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8">
<rect key="frame" x="17" y="297" width="58" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Subject:" id="18">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7"> <textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7">
<rect key="frame" x="17" y="262" width="66" height="17"/> <rect key="frame" x="17" y="262" width="272" height="17"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Message:" id="19"> <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Describe what you were doing:" id="19">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@ -61,15 +81,15 @@
<rect key="frame" x="20" y="55" width="440" height="199"/> <rect key="frame" x="20" y="55" width="440" height="199"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<clipView key="contentView" drawsBackground="NO" id="tK9-bv-5OD"> <clipView key="contentView" drawsBackground="NO" id="tK9-bv-5OD">
<rect key="frame" x="1" y="1" width="438" height="197"/> <rect key="frame" x="1" y="1" width="423" height="197"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textView importsGraphics="NO" verticallyResizable="YES" usesFontPanel="YES" findStyle="panel" continuousSpellChecking="YES" usesRuler="YES" smartInsertDelete="YES" id="15"> <textView importsGraphics="NO" verticallyResizable="YES" usesFontPanel="YES" findStyle="panel" continuousSpellChecking="YES" usesRuler="YES" smartInsertDelete="YES" id="15">
<rect key="frame" x="0.0" y="0.0" width="438" height="197"/> <rect key="frame" x="0.0" y="0.0" width="423" height="197"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="438" height="197"/> <size key="minSize" width="423" height="197"/>
<size key="maxSize" width="863" height="10000000"/> <size key="maxSize" width="863" height="10000000"/>
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
</textView> </textView>
@ -80,7 +100,7 @@
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</scroller> </scroller>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="14"> <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="14">
<rect key="frame" x="423" y="1" width="16" height="197"/> <rect key="frame" x="424" y="1" width="15" height="197"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</scroller> </scroller>
<connections> <connections>
@ -111,31 +131,6 @@
<outlet property="nextKeyView" destination="5" id="28"/> <outlet property="nextKeyView" destination="5" id="28"/>
</connections> </connections>
</button> </button>
<progressIndicator horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" maxValue="100" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="12">
<rect key="frame" x="444" y="340" width="16" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</progressIndicator>
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5">
<rect key="frame" x="80" y="337" width="356" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="21">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="nextKeyView" destination="10" id="33"/>
</connections>
</textField>
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4">
<rect key="frame" x="17" y="339" width="71" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Email:" id="22">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews> </subviews>
</view> </view>
<connections> <connections>

View file

@ -143,6 +143,7 @@
837DC931285B3F790005C58A /* DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 837DC92F285B3F790005C58A /* DataModel.xcdatamodeld */; }; 837DC931285B3F790005C58A /* DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 837DC92F285B3F790005C58A /* DataModel.xcdatamodeld */; };
8381A09227C5F72F00A1C530 /* SHA256Digest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8381A09127C5F72F00A1C530 /* SHA256Digest.m */; }; 8381A09227C5F72F00A1C530 /* SHA256Digest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8381A09127C5F72F00A1C530 /* SHA256Digest.m */; };
8384914018083E4E00E7332D /* filetype.icns in Resources */ = {isa = PBXBuildFile; fileRef = 8384913D18083E4E00E7332D /* filetype.icns */; }; 8384914018083E4E00E7332D /* filetype.icns in Resources */ = {isa = PBXBuildFile; fileRef = 8384913D18083E4E00E7332D /* filetype.icns */; };
838770FA2D6F0996001455A0 /* FeedbackController.m in Sources */ = {isa = PBXBuildFile; fileRef = 838770F42D6F0996001455A0 /* FeedbackController.m */; };
838A33742D06A9B100D0D770 /* librubberband.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 838A33732D06A9B100D0D770 /* librubberband.3.dylib */; }; 838A33742D06A9B100D0D770 /* librubberband.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 838A33732D06A9B100D0D770 /* librubberband.3.dylib */; };
838A33752D06A9CE00D0D770 /* librubberband.3.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 838A33732D06A9B100D0D770 /* librubberband.3.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 838A33752D06A9CE00D0D770 /* librubberband.3.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 838A33732D06A9B100D0D770 /* librubberband.3.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
838A337D2D06C14200D0D770 /* TempoSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 838A337C2D06C14200D0D770 /* TempoSlider.m */; }; 838A337D2D06C14200D0D770 /* TempoSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 838A337C2D06C14200D0D770 /* TempoSlider.m */; };
@ -155,9 +156,6 @@
83922FBA286B1AA900A0B039 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83922FB6286B1AA900A0B039 /* WebKit.framework */; }; 83922FBA286B1AA900A0B039 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83922FB6286B1AA900A0B039 /* WebKit.framework */; };
839614A2286ED97200D3EEDB /* AboutWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 839614A0286ED97200D3EEDB /* AboutWindowController.xib */; }; 839614A2286ED97200D3EEDB /* AboutWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 839614A0286ED97200D3EEDB /* AboutWindowController.xib */; };
839614AD286EDA5C00D3EEDB /* SpectrumWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 839614AB286EDA5C00D3EEDB /* SpectrumWindow.xib */; }; 839614AD286EDA5C00D3EEDB /* SpectrumWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 839614AB286EDA5C00D3EEDB /* SpectrumWindow.xib */; };
83978E16285C58190076ED21 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 83978E15285C58190076ED21 /* FirebaseCrashlytics */; };
83978E26285C596F0076ED21 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 83978E25285C596F0076ED21 /* FirebaseAnalytics */; };
83978E29285C5C0A0076ED21 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 83978E28285C5C0A0076ED21 /* GoogleService-Info.plist */; };
83988F0E27BE0A5900A0E89A /* RedundantPlaylistDataStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 83988F0D27BE0A5900A0E89A /* RedundantPlaylistDataStore.m */; }; 83988F0E27BE0A5900A0E89A /* RedundantPlaylistDataStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 83988F0D27BE0A5900A0E89A /* RedundantPlaylistDataStore.m */; };
8399D4E21805A55000B503B1 /* XmlContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8399D4E01805A55000B503B1 /* XmlContainer.m */; }; 8399D4E21805A55000B503B1 /* XmlContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8399D4E01805A55000B503B1 /* XmlContainer.m */; };
839B837F286D7F8D00F529EE /* NumberHertzToStringTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839B837E286D7F8D00F529EE /* NumberHertzToStringTransformer.swift */; }; 839B837F286D7F8D00F529EE /* NumberHertzToStringTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839B837E286D7F8D00F529EE /* NumberHertzToStringTransformer.swift */; };
@ -184,6 +182,7 @@
83BCB8DE17FC971300760340 /* FFMPEG.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = B09E94350D747F7B0064F138 /* FFMPEG.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 83BCB8DE17FC971300760340 /* FFMPEG.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = B09E94350D747F7B0064F138 /* FFMPEG.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
83D0380F24A40DFB004CF90F /* CogAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83D0380E24A40DF2004CF90F /* CogAssets.xcassets */; }; 83D0380F24A40DFB004CF90F /* CogAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83D0380E24A40DF2004CF90F /* CogAssets.xcassets */; };
83F9D8071A884C54007ABEC2 /* SilenceDecoder.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83F9D7F61A884B46007ABEC2 /* SilenceDecoder.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 83F9D8071A884C54007ABEC2 /* SilenceDecoder.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83F9D7F61A884B46007ABEC2 /* SilenceDecoder.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
83F9FFEF2D6EB75B00026576 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 83F9FFEE2D6EB75B00026576 /* Sentry */; };
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
@ -198,7 +197,7 @@
8E8D41C80CBB0DA900135C1B /* Pls.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E8D41C70CBB0DA000135C1B /* Pls.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 8E8D41C80CBB0DA900135C1B /* Pls.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8E8D41C70CBB0DA000135C1B /* Pls.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E9A30140BA792DC0091081B /* NSFileHandle+CreateFile.m */; }; 8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E9A30140BA792DC0091081B /* NSFileHandle+CreateFile.m */; };
99EAACA80DD1BB7A00423C38 /* APL.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 566D321B0D538550004466A5 /* APL.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 99EAACA80DD1BB7A00423C38 /* APL.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 566D321B0D538550004466A5 /* APL.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
ED69CA3B25BE2A390090B90D /* Preferences.preferencePane in CopyFiles */ = {isa = PBXBuildFile; fileRef = 17F5622E0C3BD8FB0019975C /* Preferences.preferencePane */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; ED69CA3B25BE2A390090B90D /* Preferences.preferencePane in Copy Files */ = {isa = PBXBuildFile; fileRef = 17F5622E0C3BD8FB0019975C /* Preferences.preferencePane */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
ED69CBC725BE32C00090B90D /* MASShortcut.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED69CBBF25BE328C0090B90D /* MASShortcut.framework */; }; ED69CBC725BE32C00090B90D /* MASShortcut.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED69CBBF25BE328C0090B90D /* MASShortcut.framework */; };
ED69CBCA25BE32E80090B90D /* MASShortcut.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = ED69CBBF25BE328C0090B90D /* MASShortcut.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; ED69CBCA25BE32E80090B90D /* MASShortcut.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = ED69CBBF25BE328C0090B90D /* MASShortcut.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EDAAA41F25A665C000731773 /* PositionSliderToolbarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAAA41E25A665C000731773 /* PositionSliderToolbarItem.swift */; }; EDAAA41F25A665C000731773 /* PositionSliderToolbarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAAA41E25A665C000731773 /* PositionSliderToolbarItem.swift */; };
@ -664,14 +663,15 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
07DFC3930ECDF80100DA400D /* CopyFiles */ = { 07DFC3930ECDF80100DA400D /* Copy Files */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
dstPath = ""; dstPath = "";
dstSubfolderSpec = 7; dstSubfolderSpec = 7;
files = ( files = (
ED69CA3B25BE2A390090B90D /* Preferences.preferencePane in CopyFiles */, ED69CA3B25BE2A390090B90D /* Preferences.preferencePane in Copy Files */,
); );
name = "Copy Files";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
177FD1000B90CB570011C3B5 /* CopyFiles */ = { 177FD1000B90CB570011C3B5 /* CopyFiles */ = {
@ -972,6 +972,8 @@
8384912518080F2D00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; }; 8384912518080F2D00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; };
8384913D18083E4E00E7332D /* filetype.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = filetype.icns; sourceTree = "<group>"; }; 8384913D18083E4E00E7332D /* filetype.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = filetype.icns; sourceTree = "<group>"; };
83859520234FEB35004E9946 /* Cog.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Cog.entitlements; sourceTree = "<group>"; }; 83859520234FEB35004E9946 /* Cog.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Cog.entitlements; sourceTree = "<group>"; };
838770F32D6F0996001455A0 /* FeedbackController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FeedbackController.h; sourceTree = "<group>"; };
838770F42D6F0996001455A0 /* FeedbackController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FeedbackController.m; sourceTree = "<group>"; };
838A33732D06A9B100D0D770 /* librubberband.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = librubberband.3.dylib; path = ThirdParty/rubberband/lib/librubberband.3.dylib; sourceTree = "<group>"; }; 838A33732D06A9B100D0D770 /* librubberband.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = librubberband.3.dylib; path = ThirdParty/rubberband/lib/librubberband.3.dylib; sourceTree = "<group>"; };
838A33792D06C14200D0D770 /* PitchSlider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PitchSlider.h; path = Window/PitchSlider.h; sourceTree = "<group>"; }; 838A33792D06C14200D0D770 /* PitchSlider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PitchSlider.h; path = Window/PitchSlider.h; sourceTree = "<group>"; };
838A337A2D06C14200D0D770 /* PitchSlider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PitchSlider.m; path = Window/PitchSlider.m; sourceTree = "<group>"; }; 838A337A2D06C14200D0D770 /* PitchSlider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PitchSlider.m; path = Window/PitchSlider.m; sourceTree = "<group>"; };
@ -996,7 +998,6 @@
839614AC286EDA5C00D3EEDB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SpectrumWindow.xib; sourceTree = "<group>"; }; 839614AC286EDA5C00D3EEDB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SpectrumWindow.xib; sourceTree = "<group>"; };
839614AF286EDA6800D3EEDB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/SpectrumWindow.strings; sourceTree = "<group>"; }; 839614AF286EDA6800D3EEDB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/SpectrumWindow.strings; sourceTree = "<group>"; };
839614B1286EDA6E00D3EEDB /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/SpectrumWindow.strings; sourceTree = "<group>"; }; 839614B1286EDA6E00D3EEDB /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/SpectrumWindow.strings; sourceTree = "<group>"; };
83978E28285C5C0A0076ED21 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
83988F0C27BE0A5900A0E89A /* RedundantPlaylistDataStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RedundantPlaylistDataStore.h; sourceTree = "<group>"; }; 83988F0C27BE0A5900A0E89A /* RedundantPlaylistDataStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RedundantPlaylistDataStore.h; sourceTree = "<group>"; };
83988F0D27BE0A5900A0E89A /* RedundantPlaylistDataStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RedundantPlaylistDataStore.m; sourceTree = "<group>"; }; 83988F0D27BE0A5900A0E89A /* RedundantPlaylistDataStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RedundantPlaylistDataStore.m; sourceTree = "<group>"; };
8399D4E01805A55000B503B1 /* XmlContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XmlContainer.m; sourceTree = "<group>"; }; 8399D4E01805A55000B503B1 /* XmlContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XmlContainer.m; sourceTree = "<group>"; };
@ -1085,12 +1086,11 @@
835FAC7E27BCDF5B00BA8562 /* libaom.a in Frameworks */, 835FAC7E27BCDF5B00BA8562 /* libaom.a in Frameworks */,
837DC92B285B05710005C58A /* CoreData.framework in Frameworks */, 837DC92B285B05710005C58A /* CoreData.framework in Frameworks */,
838A33742D06A9B100D0D770 /* librubberband.3.dylib in Frameworks */, 838A33742D06A9B100D0D770 /* librubberband.3.dylib in Frameworks */,
83978E26285C596F0076ED21 /* FirebaseAnalytics in Frameworks */,
17BB5CF90B8A86350009ACB1 /* AudioUnit.framework in Frameworks */, 17BB5CF90B8A86350009ACB1 /* AudioUnit.framework in Frameworks */,
17BB5CFA0B8A86350009ACB1 /* CoreAudio.framework in Frameworks */, 17BB5CFA0B8A86350009ACB1 /* CoreAudio.framework in Frameworks */,
838F851E256B4E5E00C3E614 /* Sparkle.framework in Frameworks */, 838F851E256B4E5E00C3E614 /* Sparkle.framework in Frameworks */,
83F9FFEF2D6EB75B00026576 /* Sentry in Frameworks */,
17BB5CFB0B8A86350009ACB1 /* CoreAudioKit.framework in Frameworks */, 17BB5CFB0B8A86350009ACB1 /* CoreAudioKit.framework in Frameworks */,
83978E16285C58190076ED21 /* FirebaseCrashlytics in Frameworks */,
17BB5EA60B8A87850009ACB1 /* IOKit.framework in Frameworks */, 17BB5EA60B8A87850009ACB1 /* IOKit.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -1110,6 +1110,7 @@
080E96DDFE201D6D7F000001 /* Classes */ = { 080E96DDFE201D6D7F000001 /* Classes */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
838770F72D6F0996001455A0 /* Feedback */,
835F00B3279BD1CD00055FCF /* Formatters */, 835F00B3279BD1CD00055FCF /* Formatters */,
177042960B8BC53600B86321 /* Application */, 177042960B8BC53600B86321 /* Application */,
17E0D5D20F520E75005B6FED /* Window */, 17E0D5D20F520E75005B6FED /* Window */,
@ -1468,7 +1469,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0A1B412E286F6301008A6A44 /* Localizable.stringsdict */, 0A1B412E286F6301008A6A44 /* Localizable.stringsdict */,
83978E28285C5C0A0076ED21 /* GoogleService-Info.plist */,
83D0380E24A40DF2004CF90F /* CogAssets.xcassets */, 83D0380E24A40DF2004CF90F /* CogAssets.xcassets */,
83859520234FEB35004E9946 /* Cog.entitlements */, 83859520234FEB35004E9946 /* Cog.entitlements */,
080E96DDFE201D6D7F000001 /* Classes */, 080E96DDFE201D6D7F000001 /* Classes */,
@ -1804,6 +1804,15 @@
name = Visualization; name = Visualization;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
838770F72D6F0996001455A0 /* Feedback */ = {
isa = PBXGroup;
children = (
838770F32D6F0996001455A0 /* FeedbackController.h */,
838770F42D6F0996001455A0 /* FeedbackController.m */,
);
path = Feedback;
sourceTree = "<group>";
};
83B0669D180D5668008E3612 /* Products */ = { 83B0669D180D5668008E3612 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1975,8 +1984,8 @@
8D1107290486CEB800E47090 /* Resources */, 8D1107290486CEB800E47090 /* Resources */,
8E757AEC09F3265E0080F1EE /* CopyFiles */, 8E757AEC09F3265E0080F1EE /* CopyFiles */,
177FD1000B90CB570011C3B5 /* CopyFiles */, 177FD1000B90CB570011C3B5 /* CopyFiles */,
07DFC3930ECDF80100DA400D /* CopyFiles */, 07DFC3930ECDF80100DA400D /* Copy Files */,
83978E27285C5A4C0076ED21 /* Run Crashlytics symbol upload */, 83978E27285C5A4C0076ED21 /* Run Sentry symbol upload */,
); );
buildRules = ( buildRules = (
); );
@ -2015,8 +2024,7 @@
); );
name = Cog; name = Cog;
packageProductDependencies = ( packageProductDependencies = (
83978E15285C58190076ED21 /* FirebaseCrashlytics */, 83F9FFEE2D6EB75B00026576 /* Sentry */,
83978E25285C596F0076ED21 /* FirebaseAnalytics */,
); );
productInstallPath = /Applications; productInstallPath = /Applications;
productName = Cog; productName = Cog;
@ -2060,7 +2068,7 @@
); );
mainGroup = 29B97314FDCFA39411CA2CEA /* Cog */; mainGroup = 29B97314FDCFA39411CA2CEA /* Cog */;
packageReferences = ( packageReferences = (
83978E14285C58190076ED21 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, 83F9FFED2D6EB75B00026576 /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
); );
projectDirPath = ""; projectDirPath = "";
projectReferences = ( projectReferences = (
@ -2483,7 +2491,6 @@
832923AF279FAC400048201E /* Cog.q1.json in Resources */, 832923AF279FAC400048201E /* Cog.q1.json in Resources */,
17D1B2820CF8B2830028F5B5 /* vg.icns in Resources */, 17D1B2820CF8B2830028F5B5 /* vg.icns in Resources */,
17D1B2830CF8B2830028F5B5 /* xm.icns in Resources */, 17D1B2830CF8B2830028F5B5 /* xm.icns in Resources */,
83978E29285C5C0A0076ED21 /* GoogleService-Info.plist in Resources */,
836DF61E298F7F6E00CD0580 /* Scenes.scnassets in Resources */, 836DF61E298F7F6E00CD0580 /* Scenes.scnassets in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -2510,7 +2517,7 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "$SCRIPT_INPUT_FILE_0 $SCRIPT_INPUT_FILE_1 $SCRIPT_OUTPUT_FILE_0\n"; shellScript = "$SCRIPT_INPUT_FILE_0 $SCRIPT_INPUT_FILE_1 $SCRIPT_OUTPUT_FILE_0\n";
}; };
83978E27285C5A4C0076ED21 /* Run Crashlytics symbol upload */ = { 83978E27285C5A4C0076ED21 /* Run Sentry symbol upload */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
buildActionMask = 12; buildActionMask = 12;
@ -2522,14 +2529,14 @@
"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}",
"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
); );
name = "Run Crashlytics symbol upload"; name = "Run Sentry symbol upload";
outputFileListPaths = ( outputFileListPaths = (
); );
outputPaths = ( outputPaths = (
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "if [[ \"${CONFIGURATION}\" = \"Release\" ]] || [[ \"${CONFIGURATION}\" = \"Adhoc\" ]]; then\n echo \"Uploading dSYMs...\"\n find \"${DWARF_DSYM_FOLDER_PATH}\" -name \"*.dSYM\" -print0 | xargs -0 -I \\{\\} \"${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/upload-symbols\" -gsp \"${SRCROOT}/GoogleService-Info.plist\" -p mac \\{\\}\nelse\n echo \"Skip dSYMs upload\"\nfi\n\nexit 0\n"; shellScript = "if [[ \"x${SENTRY_URL}\" != \"x\" ]] && [[ \"x${SENTRY_PROJECT}\" != \"x\" ]] && [[ \"x${SENTRY_AUTH_TOKEN}\" != \"x\" ]]; then\n if [[ \"${CONFIGURATION}\" = \"Release\" ]] || [[ \"${CONFIGURATION}\" = \"Adhoc\" ]]; then\n echo \"Uploading dSYMs...\"\n export PATH=$PATH:/usr/local/bin:/opt/homebrew/bin\n sentry-cli --url \"${SENTRY_URL}\" debug-files upload -p \"${SENTRY_PROJECT}\" --auth-token \"${SENTRY_AUTH_TOKEN}\" --include-sources \"${DWARF_DSYM_FOLDER_PATH}\"\n else\n echo \"Skip dSYMs upload\"\n fi\nelse\n echo \"Sentry settings not configured\"\nfi\n\nexit 0\n";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@ -2558,6 +2565,7 @@
1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */, 1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */,
8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */, 8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */,
179790E10C087AB7001D6996 /* OpenURLPanel.m in Sources */, 179790E10C087AB7001D6996 /* OpenURLPanel.m in Sources */,
838770FA2D6F0996001455A0 /* FeedbackController.m in Sources */,
837DC931285B3F790005C58A /* DataModel.xcdatamodeld in Sources */, 837DC931285B3F790005C58A /* DataModel.xcdatamodeld in Sources */,
835FAC7927BCDF2A00BA8562 /* AVIFDecoder.m in Sources */, 835FAC7927BCDF2A00BA8562 /* AVIFDecoder.m in Sources */,
EDAAA41F25A665C000731773 /* PositionSliderToolbarItem.swift in Sources */, EDAAA41F25A665C000731773 /* PositionSliderToolbarItem.swift in Sources */,
@ -3163,26 +3171,21 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
83978E14285C58190076ED21 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { 83F9FFED2D6EB75B00026576 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; repositoryURL = "https://github.com/getsentry/sentry-cocoa.git";
requirement = { requirement = {
kind = upToNextMajorVersion; kind = upToNextMajorVersion;
minimumVersion = 10.0.0; minimumVersion = 8.45.0;
}; };
}; };
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
83978E15285C58190076ED21 /* FirebaseCrashlytics */ = { 83F9FFEE2D6EB75B00026576 /* Sentry */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 83978E14285C58190076ED21 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; package = 83F9FFED2D6EB75B00026576 /* XCRemoteSwiftPackageReference "sentry-cocoa" */;
productName = FirebaseCrashlytics; productName = Sentry;
};
83978E25285C596F0076ED21 /* FirebaseAnalytics */ = {
isa = XCSwiftPackageProductDependency;
package = 83978E14285C58190076ED21 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseAnalytics;
}; };
/* End XCSwiftPackageProductDependency section */ /* End XCSwiftPackageProductDependency section */

View file

@ -1,123 +1,15 @@
{ {
"originHash" : "c63c63846d9c539229e96de38d6af51417e28c0ee9a0bc48bd0f0f19d923c329", "originHash" : "7b5e54f81ac1ebaa640945691cb38c371b637198701f04fba811702fc8e7067e",
"pins" : [ "pins" : [
{ {
"identity" : "abseil-cpp-binary", "identity" : "sentry-cocoa",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git", "location" : "https://github.com/getsentry/sentry-cocoa.git",
"state" : { "state" : {
"revision" : "194a6706acbd25e4ef639bcaddea16e8758a3e27", "revision" : "3640aaf7849a9fc39996d777e6df866251bb98d6",
"version" : "1.2024011602.0" "version" : "8.45.0"
}
},
{
"identity" : "app-check",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "3b62f154d00019ae29a71e9738800bb6f18b236d",
"version" : "10.19.2"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "eca84fd638116dd6adb633b5a3f31cc7befcbb7d",
"version" : "10.29.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "fe727587518729046fc1465625b9afd80b5ab361",
"version" : "10.28.0"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "a637d318ae7ae246b02d7305121275bc75ed5565",
"version" : "9.4.0"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "57a1d307f42df690fdef2637f3e5b776da02aad6",
"version" : "7.13.3"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "e9fad491d0673bdda7063a0341fb6b47a30c5359",
"version" : "1.62.2"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "a2ab612cb980066ee56d90d60d8462992c07f24b",
"version" : "3.5.0"
}
},
{
"identity" : "interop-ios-for-google-sdks",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
"state" : {
"revision" : "2d12673670417654f08f5f90fdd62926dc3a2648",
"version" : "100.0.0"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
"version" : "1.22.5"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
"version" : "2.30910.0"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
"version" : "2.4.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "e17d61f26df0f0e06f58f6977ba05a097a720106",
"version" : "1.27.1"
} }
} }
], ],
"version" : 2 "version" : 3
} }

View file

@ -10,15 +10,18 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
@interface FeedbackController : NSWindowController <FeedbackSocketDelegate> { @interface FeedbackController : NSWindowController <FeedbackSocketDelegate> {
IBOutlet NSTextField* fromView; IBOutlet NSTextField* nameView;
IBOutlet NSTextField* subjectView; IBOutlet NSTextField* emailView;
IBOutlet NSTextView* messageView; IBOutlet NSTextView* messageView;
IBOutlet NSProgressIndicator* sendingIndicator;
FeedbackSocket* feedbackSocket;
} }
- (IBAction)sendFeedback:(id)sender; - (IBAction)sendFeedback:(id)sender;
- (IBAction)cancel:(id)sender; - (IBAction)cancel:(id)sender;
- (BOOL)waitForCompletion;
- (NSString *)name;
- (NSString *)email;
- (NSString *)comments;
@end @end

View file

@ -10,62 +10,67 @@
#import "Logging.h" #import "Logging.h"
@implementation FeedbackController @implementation FeedbackController {
BOOL showing;
BOOL sent;
NSString *name;
NSString *email;
NSString *comments;
}
- (id)init { - (id)init {
return [super initWithWindowNibName:@"Feedback"]; self = [super initWithWindowNibName:@"Feedback"];
if(self) {
showing = NO;
sent = NO;
}
return self;
} }
- (IBAction)showWindow:(id)sender { - (IBAction)showWindow:(id)sender {
[fromView setStringValue:@""]; [nameView setStringValue:@""];
[subjectView setStringValue:@""]; [emailView setStringValue:@""];
[messageView setString:@""]; [messageView setString:@""];
[super showWindow:sender]; [super showWindow:sender];
}
showing = YES;
- (void)alertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo {
if([(NSNumber *)CFBridgingRelease(contextInfo) boolValue] == YES) {
[[self window] close];
}
}
- (void)feedbackDidNotSend:(FeedbackSocket *)feedback {
ALog(@"Error sending feedback");
[sendingIndicator stopAnimation:self];
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:NSLocalizedString(@"FeedbackFailedMessageText", @"")];
[alert setInformativeText:NSLocalizedString(@"FeedbackFailedInformativeText", @"")];
[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:(void *)CFBridgingRetain([NSNumber numberWithBool:NO])];
}
- (void)feedbackDidSend:(FeedbackSocket *)feedback {
[sendingIndicator stopAnimation:self];
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:NSLocalizedString(@"FeedbackSuccessMessageText", @"")];
[alert setInformativeText:NSLocalizedString(@"FeedbackSuccessInformativeText", @"")];
[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:(void *)CFBridgingRetain([NSNumber numberWithBool:YES])];
} }
- (IBAction)sendFeedback:(id)sender { - (IBAction)sendFeedback:(id)sender {
[sendingIndicator startAnimation:self]; name = [nameView stringValue];
email = [emailView stringValue];
comments = [messageView string];
// Using this so that if its a bad connection, it doesnt sit there looking stupid..or should it [[self window] close];
feedbackSocket = [[FeedbackSocket alloc] init]; sent = YES;
[feedbackSocket setDelegate:self]; showing = NO;
NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
[feedbackSocket sendFeedback:[fromView stringValue] subject:[subjectView stringValue] message:[messageView string] version:version];
} }
- (IBAction)cancel:(id)sender { - (IBAction)cancel:(id)sender {
[[self window] close]; [[self window] close];
sent = NO;
showing = NO;
}
- (BOOL)waitForCompletion {
while(showing) {
usleep(2000);
}
return sent;
}
- (NSString *)name {
return name;
}
- (NSString *)email {
return email;
}
- (NSString *)comments {
return comments;
} }
@end @end

View file

@ -2,8 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>FirebaseCrashlyticsCollectionEnabled</key>
<false/>
<key>SUEnableInstallerLauncherService</key> <key>SUEnableInstallerLauncherService</key>
<true/> <true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>

View file

@ -41,8 +41,6 @@
#import "SandboxBroker.h" #import "SandboxBroker.h"
@import Firebase;
extern NSMutableDictionary<NSString *, AlbumArtwork *> *kArtworkDictionary; extern NSMutableDictionary<NSString *, AlbumArtwork *> *kArtworkDictionary;
@implementation PlaylistLoader @implementation PlaylistLoader
@ -748,7 +746,7 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
[op addExecutionBlock:^{ [op addExecutionBlock:^{
@autoreleasepool { @autoreleasepool {
DLog(@"Loading metadata for %@", url); DLog(@"Loading metadata for %@", url);
[[FIRCrashlytics crashlytics] logWithFormat:@"Loading metadata for %@", url]; //[[FIRCrashlytics crashlytics] logWithFormat:@"Loading metadata for %@", url];
NSDictionary *entryProperties = [AudioPropertiesReader propertiesForURL:url]; NSDictionary *entryProperties = [AudioPropertiesReader propertiesForURL:url];
if(entryProperties == nil) if(entryProperties == nil)
@ -883,7 +881,7 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
PlaylistEntry *pe = [entries objectAtIndex:idx]; PlaylistEntry *pe = [entries objectAtIndex:idx];
DLog(@"Loading metadata for %@", pe.url); DLog(@"Loading metadata for %@", pe.url);
[[FIRCrashlytics crashlytics] logWithFormat:@"Loading metadata for %@", pe.url]; //[[FIRCrashlytics crashlytics] logWithFormat:@"Loading metadata for %@", pe.url];
NSDictionary *entryProperties = [AudioPropertiesReader propertiesForURL:pe.url]; NSDictionary *entryProperties = [AudioPropertiesReader propertiesForURL:pe.url];
if(entryProperties == nil) if(entryProperties == nil)

View file

@ -16,8 +16,6 @@
#import "Logging.h" #import "Logging.h"
@import Firebase;
static NSString *playlistSavedColumnsID = @"Playlist Saved Columns v0"; static NSString *playlistSavedColumnsID = @"Playlist Saved Columns v0";
@implementation PlaylistView @implementation PlaylistView
@ -121,7 +119,7 @@ static NSString *playlistSavedColumnsID = @"Playlist Saved Columns v0";
// Reset to defaults // Reset to defaults
NSString *message = @"Reset playlist columns to default"; NSString *message = @"Reset playlist columns to default";
DLog(@"%@", message); DLog(@"%@", message);
[[FIRCrashlytics crashlytics] logWithFormat:@"%@", message]; //[[FIRCrashlytics crashlytics] logWithFormat:@"%@", message];
for(NSTableColumn *col in columns) { for(NSTableColumn *col in columns) {
[self removeTableColumn:col]; [self removeTableColumn:col];
} }

View file

@ -461,7 +461,7 @@
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
</buttonCell> </buttonCell>
<connections> <connections>
<binding destination="52" name="value" keyPath="values.crashlyticsConsented" id="GQu-a0-JJs"/> <binding destination="52" name="value" keyPath="values.sentryConsented" id="7I0-0u-zKC"/>
</connections> </connections>
</button> </button>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="crf-C9-9YF"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="crf-C9-9YF">

View file

@ -16,26 +16,26 @@
// For instance, for the first option to get this treatment, we want time stretching to stay enabled // For instance, for the first option to get this treatment, we want time stretching to stay enabled
// for existing installations, but disable itself by default on new installs, to spare processing. // for existing installations, but disable itself by default on new installs, to spare processing.
void showCrashlyticsConsent(NSWindow *window) { void showSentryConsent(NSWindow *window) {
BOOL askedConsent = [[NSUserDefaults standardUserDefaults] boolForKey:@"crashlyticsAskedConsent"]; BOOL askedConsent = [[NSUserDefaults standardUserDefaults] boolForKey:@"sentryAskedConsent"];
if(!askedConsent) { if(!askedConsent) {
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"rubberbandEngine": @"disabled" }]; [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"rubberbandEngine": @"disabled" }];
[window orderFront:window]; [window orderFront:window];
NSAlert *alert = [[NSAlert alloc] init]; NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:NSLocalizedString(@"CrashlyticsConsentTitle", @"")]; [alert setMessageText:NSLocalizedString(@"SentryConsentTitle", @"")];
[alert setInformativeText:NSLocalizedString(@"CrashlyticsConsentText", @"")]; [alert setInformativeText:NSLocalizedString(@"SentryConsentText", @"")];
[alert addButtonWithTitle:NSLocalizedString(@"ConsentYes",@"")]; [alert addButtonWithTitle:NSLocalizedString(@"ConsentYes",@"")];
[alert addButtonWithTitle:NSLocalizedString(@"ConsentNo", @"")]; [alert addButtonWithTitle:NSLocalizedString(@"ConsentNo", @"")];
[alert beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) { [alert beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {
if(returnCode == NSAlertFirstButtonReturn) { if(returnCode == NSAlertFirstButtonReturn) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"crashlyticsConsented"]; [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"sentryConsented"];
} }
}]; }];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"crashlyticsAskedConsent"]; [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"sentryAskedConsent"];
} else { } else {
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"rubberbandEngine": @"faster" }]; [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"rubberbandEngine": @"faster" }];
} }
@ -62,7 +62,7 @@ void showCrashlyticsConsent(NSWindow *window) {
[self showHDCDLogo:NO]; [self showHDCDLogo:NO];
if(![[NSUserDefaults standardUserDefaults] boolForKey:@"miniMode"]) { if(![[NSUserDefaults standardUserDefaults] boolForKey:@"miniMode"]) {
showCrashlyticsConsent(self); showSentryConsent(self);
} }
} }

View file

@ -12,7 +12,7 @@
extern NSString *iTunesDropType; extern NSString *iTunesDropType;
extern void showCrashlyticsConsent(NSWindow *window); extern void showSentryConsent(NSWindow *window);
@implementation MiniWindow @implementation MiniWindow
@ -44,7 +44,7 @@ extern void showCrashlyticsConsent(NSWindow *window);
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL, iTunesDropType]]; [self registerForDraggedTypes:@[NSPasteboardTypeFileURL, iTunesDropType]];
if([[NSUserDefaults standardUserDefaults] boolForKey:@"miniMode"]) { if([[NSUserDefaults standardUserDefaults] boolForKey:@"miniMode"]) {
showCrashlyticsConsent(self); showSentryConsent(self);
} }
} }

View file

@ -47,3 +47,8 @@
// CODE_SIGN_IDENTITY = …; // CODE_SIGN_IDENTITY = …;
// CODE_SIGN_STYLE = Manual/Automatic; // CODE_SIGN_STYLE = Manual/Automatic;
// Please make sure not to commit them to source control. // Please make sure not to commit them to source control.
#include? "SENTRY_SETTINGS.xcconfig"
// Also, create this file if you wish to upload symbols to your server on build.
// It should define SENTRY_URL, SENTRY_PROJECT to the ID number, and finally
// SENTRY_AUTH_TOKEN to the developer authorization token for your instance.

View file

@ -1,15 +1,15 @@
/* Class = "NSWindow"; title = "Send Feedback"; ObjectID = "1"; */ /* Class = "NSWindow"; title = "Send Crash Feedback"; ObjectID = "1"; */
"1.title" = "Send Feedback"; "1.title" = "Send Crash Feedback";
/* Class = "NSButtonCell"; title = "Send"; ObjectID = "17"; */ /* Class = "NSButtonCell"; title = "Send"; ObjectID = "17"; */
"17.title" = "Send"; "17.title" = "Send";
/* Class = "NSTextFieldCell"; title = "Subject:"; ObjectID = "18"; */ /* Class = "NSTextFieldCell"; title = "Name:"; ObjectID = "18"; */
"18.title" = "Subject:"; "18.title" = "Name:";
/* Class = "NSTextFieldCell"; title = "Message:"; ObjectID = "19"; */ /* Class = "NSTextFieldCell"; title = "Describe what you were doing:"; ObjectID = "19"; */
"19.title" = "Message:"; "19.title" = "Describe what you were doing:";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "20"; */ /* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "20"; */
"20.title" = "Cancel"; "20.title" = "Cancel";

View file

@ -2,8 +2,8 @@
"CogTitle" = "Cog"; "CogTitle" = "Cog";
"ConsentNo" = "No"; "ConsentNo" = "No";
"ConsentYes" = "Yes"; "ConsentYes" = "Yes";
"CrashlyticsConsentText" = "Would you like to allow Crashlytics to submit crash reports? You may turn this off again in Preferences. We won't ask you again."; "SentryConsentText" = "Would you like to allow Sentry to submit crash reports? You may turn this off again in Preferences. We won't ask you again.";
"CrashlyticsConsentTitle" = "Crashlytics crash collection"; "SentryConsentTitle" = "Sentry crash collection";
"ErrorInvalidTrackId" = "Invalid track ID sent to SQLite request."; "ErrorInvalidTrackId" = "Invalid track ID sent to SQLite request.";
"ErrorMessageBadFile" = "Unable to parse metadata for bad file."; "ErrorMessageBadFile" = "Unable to parse metadata for bad file.";
"ErrorMetadata" = "Unable to retrieve metadata."; "ErrorMetadata" = "Unable to retrieve metadata.";

View file

@ -1,18 +1,18 @@
/* Class = "NSWindow"; title = "Send Feedback"; ObjectID = "1"; */ /* Class = "NSWindow"; title = "Send Crash Feedback"; ObjectID = "1"; */
"1.title" = "Enviar comentarios"; "1.title" = "Enviar comentarios por fallo";
/* Class = "NSButtonCell"; title = "Send"; ObjectID = "17"; */ /* Class = "NSButtonCell"; title = "Send"; ObjectID = "17"; */
"17.title" = "Enviar"; "17.title" = "Enviar";
/* Class = "NSTextFieldCell"; title = "Subject:"; ObjectID = "18"; */ /* Class = "NSTextFieldCell"; title = "Name:"; ObjectID = "18"; */
"18.title" = "Asunto:"; "18.title" = "Nombre:";
/* Class = "NSTextFieldCell"; title = "Message:"; ObjectID = "19"; */ /* Class = "NSTextFieldCell"; title = "Describe what you were doing:"; ObjectID = "19"; */
"19.title" = "Mensaje:"; "19.title" = "Describe lo que estabas haciendo:";
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "20"; */ /* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "20"; */
"20.title" = "Cancelar"; "20.title" = "Cancelar";
/* Class = "NSTextFieldCell"; title = "Email:"; ObjectID = "22"; */ /* Class = "NSTextFieldCell"; title = "Email:"; ObjectID = "22"; */
"22.title" = "Correo electrónico:"; "22.title" = "Email:";

View file

@ -2,8 +2,8 @@
"CogTitle" = "Cog"; "CogTitle" = "Cog";
"ConsentNo" = "No"; "ConsentNo" = "No";
"ConsentYes" = "Sí"; "ConsentYes" = "Sí";
"CrashlyticsConsentText" = "¿Te gustaría permitir que Crashlytics envíe informes de fallos? Puedes volver a desactivarlo en Preferencias. No te volveremos a preguntar."; "SentryConsentText" = "¿Te gustaría permitir que Sentry envíe informes de fallos? Puedes volver a desactivarlo en Preferencias. No te volveremos a preguntar.";
"CrashlyticsConsentTitle" = "Colección de fallos de Crashlytics"; "CrashlyticsConsentTitle" = "Colección de fallos de Sentry";
"ErrorInvalidTrackId" = "ID de pista inválida enviada a la solicitud de SQLite."; "ErrorInvalidTrackId" = "ID de pista inválida enviada a la solicitud de SQLite.";
"ErrorMessageBadFile" = "No se han podido analizar los metadatos de un archivo defectuoso."; "ErrorMessageBadFile" = "No se han podido analizar los metadatos de un archivo defectuoso.";
"ErrorMetadata" = "No se pueden recuperar los metadatos."; "ErrorMetadata" = "No se pueden recuperar los metadatos.";