├── .gitignore
├── .gitmodules
├── LICENSE
├── Podfile
├── Podfile.lock
├── README.md
├── diumoo.xcodeproj
└── project.pbxproj
├── diumoo
├── DMApp.h
├── DMApp.m
├── DMAppDelegate.h
├── DMAppDelegate.m
├── DMDocument
│ ├── DMDocument.h
│ ├── DMDocument.m
│ ├── DMDocumentWindowController
│ │ ├── DMDetailViewController
│ │ │ ├── DMDetailViewController.h
│ │ │ └── DMDetailViewController.m
│ │ ├── DMDocumentWindowController.h
│ │ ├── DMDocumentWindowController.m
│ │ ├── en.lproj
│ │ │ └── DMDocumentWindow.xib
│ │ └── zh-Hans.lproj
│ │ │ └── DMDocumentWindow.xib
│ └── JUInspectorView
│ │ ├── JUInspectorBaseView.h
│ │ ├── JUInspectorBaseView.m
│ │ ├── JUInspectorView.h
│ │ ├── JUInspectorView.m
│ │ ├── JUInspectorViewContainer.h
│ │ ├── JUInspectorViewContainer.m
│ │ ├── JUInspectorViewHeader.h
│ │ └── JUInspectorViewHeader.m
├── core
│ ├── DMAuthHelper.swift
│ ├── DMControlCenter
│ │ ├── DMControlCenter.h
│ │ └── DMControlCenter.m
│ ├── DMErrorLog
│ │ ├── DMErrorLog.h
│ │ └── DMErrorLog.m
│ ├── DMNotificationCenter.swift
│ ├── DMPlayRecordHandler
│ │ ├── DMPlayRecordHandler.h
│ │ ├── DMPlayRecordHandler.m
│ │ └── DMPlayRecordModel.xcdatamodeld
│ │ │ ├── .xccurrentversion
│ │ │ └── DMPlayRecordModel.xcdatamodel
│ │ │ └── contents
│ ├── DMPlayableItem.swift
│ ├── DMPlaylistFetcher.swift
│ ├── DMService
│ │ ├── DMService.h
│ │ └── DMService.m
│ ├── DMShortcutsHandler
│ │ ├── DMShortcutsHandler.h
│ │ └── DMShortcutsHandler.m
│ └── DMUtils
│ │ ├── Dictionary+urlEncoding.swift
│ │ ├── NSData+AESCrypt.h
│ │ ├── NSData+AESCrypt.m
│ │ ├── NSData+Base64.h
│ │ ├── NSData+Base64.m
│ │ ├── NSDictionary+UrlEncoding.h
│ │ ├── NSDictionary+UrlEncoding.m
│ │ ├── NSImage+AsyncLoadImage.h
│ │ └── NSImage+AsyncLoadImage.m
├── debugLog.h
├── diumoo-Bridging-Header.h
├── diumoo-Info.plist
├── diumoo-Prefix.pch
├── en.lproj
│ ├── Credits.rtf
│ ├── InfoPlist.strings
│ ├── Localizable.strings
│ └── MainMenu.xib
├── main.m
├── ui
│ ├── DMPanel
│ │ ├── DMBitrateControlLayer
│ │ │ ├── DMBitrateControlLayer.h
│ │ │ └── DMBitrateControlLayer.m
│ │ ├── DMButton
│ │ │ ├── DMButton.h
│ │ │ └── DMButton.m
│ │ ├── DMCoverControlView
│ │ │ ├── DMCoverControlView.h
│ │ │ └── DMCoverControlView.m
│ │ ├── DMCoverSlide
│ │ │ ├── DMCoverSlide.h
│ │ │ └── DMCoverSlide.m
│ │ ├── DMPanel.h
│ │ ├── DMPanel.m
│ │ ├── DMPanelWindowController.h
│ │ ├── DMPanelWindowController.m
│ │ ├── DMPopUpButtonCell
│ │ │ ├── DMPopUpButtonCell.h
│ │ │ ├── DMPopUpButtonCell.m
│ │ │ ├── DMPopUpMenuController.h
│ │ │ └── DMPopUpMenuController.m
│ │ ├── DMVolumeSlideCell
│ │ │ ├── DMVolumeSlideCell.h
│ │ │ └── DMVolumeSlideCell.m
│ │ ├── en.lproj
│ │ │ └── DMPanelWindowController.xib
│ │ └── zh-Hans.lproj
│ │ │ └── DMPanelWindowController.xib
│ ├── DMPrefsPanel
│ │ ├── DMPrefsPanelDataProvider.h
│ │ ├── DMPrefsPanelDataProvider.m
│ │ ├── en.lproj
│ │ │ └── DMPrefsPanel.xib
│ │ └── zh-Hans.lproj
│ │ │ └── DMPrefsPanel.xib
│ ├── DMSearchPanel
│ │ ├── DMSearchItemView.h
│ │ ├── DMSearchItemView.m
│ │ ├── DMSearchPanelController.h
│ │ ├── DMSearchPanelController.m
│ │ ├── en.lproj
│ │ │ └── DMSearchPanelController.xib
│ │ └── zh-Hans.lproj
│ │ │ └── DMSearchPanelController.xib
│ └── DockIcon
│ │ └── DockImageProvider.swift
└── zh-Hans.lproj
│ ├── Credits.rtf
│ ├── InfoPlist.strings
│ ├── Localizable.strings
│ └── MainMenu.xib
├── extern
├── PLTabPreference
│ ├── PLTabPreferenceControl.h
│ └── PLTabPreferenceControl.m
├── SSKeychain
│ ├── LICENSE
│ ├── SSKeychain.h
│ └── SSKeychain.m
└── StatusItem
│ ├── MenubarController.h
│ ├── MenubarController.m
│ ├── StatusItemView.h
│ └── StatusItemView.m
├── resources
├── 128kbps.png
├── 128kbps@2x.png
├── 192kbps.png
├── 192kbps@2x.png
├── 64kbps.png
├── 64kbps@2x.png
├── albumfail.png
├── albumfail@2x.png
├── ban.png
├── ban@2x.png
├── ban_mouseover.png
├── ban_mouseover@2x.png
├── channels.plist
├── chrome.png
├── chrome_2x.png
├── dark-status-icon-alt.png
├── dark-status-icon-alt@2x.png
├── dark-status-icon-mixed.png
├── dark-status-icon-mixed@2x.png
├── dark-status-icon.png
├── dark-status-icon@2x.png
├── detail_icon.png
├── detail_icon@2x.png
├── douban.png
├── douban@2x.png
├── exit.png
├── exit@2x.png
├── exit_mouseover.png
├── exit_mouseover@2x.png
├── eye_icon.png
├── eye_icon@2x.png
├── facebook.png
├── facebook@2x.png
├── fanfou.png
├── fanfou@2x.png
├── firefox.png
├── firefox_2x.png
├── icon.icns
├── info_icon.png
├── info_icon@2x.png
├── menu-heart-gray.png
├── menu-heart-gray@2x.png
├── menu-heart.png
├── menu-heart@2x.png
├── pause.png
├── pause@2x.png
├── pause_mouseover.png
├── pause_mouseover@2x.png
├── play.png
├── play@2x.png
├── play_mouseover.png
├── play_mouseover@2x.png
├── pro_icon.png
├── pro_icon@2x.png
├── rate.png
├── rate@2x.png
├── rate_mouseover.png
├── rate_mouseover@2x.png
├── rate_red.png
├── rate_red@2x.png
├── record.icns
├── safari.png
├── safari_2x.png
├── search.png
├── search@2x.png
├── search_mouseover.png
├── search_mouseover@2x.png
├── settings.png
├── settings@2x.png
├── settings_mouseover.png
├── settings_mouseover@2x.png
├── share.png
├── share@2x.png
├── sina.png
├── sina@2x.png
├── skip.png
├── skip@2x.png
├── skip_mouseover.png
├── skip_mouseover@2x.png
├── status-icon-alt.png
├── status-icon-alt@2x.png
├── status-icon-mixed.png
├── status-icon-mixed@2x.png
├── status-icon.png
├── status-icon@2x.png
├── time_machine.png
├── time_machine@2x.png
├── twitter.png
├── twitter@2x.png
├── view_icon.png
├── view_icon@2x.png
├── volume_back.png
├── volume_back@2x.png
├── volume_slider.png
└── volume_slider@2x.png
└── third-party
├── SMTabBar
├── InspectorTabBar
│ ├── NSDictionary+SMKeyValueObserving.h
│ ├── NSDictionary+SMKeyValueObserving.m
│ ├── SMBar.h
│ ├── SMBar.m
│ ├── SMTabBar.h
│ ├── SMTabBar.m
│ ├── SMTabBarButtonCell.h
│ ├── SMTabBarButtonCell.m
│ ├── SMTabBarItem.h
│ └── SMTabBarItem.m
├── README.md
└── SMTabBar.podspec
└── SPMediaKeyTap
├── README.md
├── SPInvocationGrabbing
├── NSObject+SPInvocationGrabbing.h
└── NSObject+SPInvocationGrabbing.m
├── SPMediaKeyTap.h
├── SPMediaKeyTap.m
└── SPMediaKeyTap.podspec
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | build/*
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | *.xcworkspace
13 | !default.xcworkspace
14 | xcuserdata
15 | profile
16 | *.moved-aside
17 | DerivedData
18 | Growl.framework/*
19 |
20 | Pods/
21 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "extern/MASShortcut"]
2 | path = extern/MASShortcut
3 | url = https://github.com/shpakovski/MASShortcut.git
4 | [submodule "extern/SPMediaKeyTap"]
5 | path = extern/SPMediaKeyTap
6 | url = https://github.com/nevyn/SPMediaKeyTap.git
7 | [submodule "extern/SMTabBar"]
8 | path = extern/SMTabBar
9 | url = https://github.com/smic/InspectorTabBar.git
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | diumoo - a Mac client of Douban.FM
2 | Copyright © 2016 Chase Zhang
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 |
17 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/Cocoapods/Specs.git'
2 |
3 | platform :osx, '10.10'
4 | inhibit_all_warnings!
5 |
6 | target 'diumoo' do
7 | pod 'MASShortcut', '~> 2.3.6'
8 | pod 'SMTabBar', :path => './third-party/SMTabBar'
9 | pod 'SPMediaKeyTap', :path => './third-party/SPMediaKeyTap'
10 | end
11 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - MASShortcut (2.3.6)
3 | - SMTabBar (0.0.1)
4 | - SPMediaKeyTap (0.0.1)
5 |
6 | DEPENDENCIES:
7 | - MASShortcut (~> 2.3.6)
8 | - SMTabBar (from `./third-party/SMTabBar`)
9 | - SPMediaKeyTap (from `./third-party/SPMediaKeyTap`)
10 |
11 | EXTERNAL SOURCES:
12 | SMTabBar:
13 | :path: ./third-party/SMTabBar
14 | SPMediaKeyTap:
15 | :path: ./third-party/SPMediaKeyTap
16 |
17 | SPEC CHECKSUMS:
18 | MASShortcut: 9c215e8a8a78f3d01ce56da48e2730ab66b538fa
19 | SMTabBar: 11521459249d577ef278442319c0ac4d90628d2e
20 | SPMediaKeyTap: ddb3cf0f3485bf2ac5a31c1b5ce9fc396115be7f
21 |
22 | PODFILE CHECKSUM: b0edc7bd09b1788418d857997b326ea538e805c2
23 |
24 | COCOAPODS: 1.3.1
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Diumoo
2 |
3 | Third party client of [Douban.FM](http://douban.fm) for Mac.
4 | For more details, refer to our [Homepage](http://diumoo.net).
5 |
6 | ## Why?
7 |
8 | 1. NO Flash, NO web broswer
9 | 2. Native code, battery friendly
10 | 3. Silently rest in your status bar
11 | 4. More features (Time Machine, Search, etc.)
12 |
13 | ## Installation
14 |
15 | Download [precompiled version](https://github.com/shanzi/diumoo/releases)
16 |
17 | ## Develop
18 |
19 | To contribute or compile diumoo by yourself, follow instructions below:
20 |
21 | ```
22 | git clone git@github.com:shanzi/diumoo.git
23 |
24 | git submodule init # Initialize dependencies
25 |
26 | ```
27 |
28 | Then you can open `diumoo.xcodeproj` and modify the code or compile it.
29 |
30 | Pull requests are extremely welcomed. Fork and conforms to [GitHub workflow](https://guides.github.com/introduction/flow/index.html)
31 | before contribution :)
32 |
33 | **NOTICE**: We use `master` branch for developing and new pull requests will be merged into `master`.
34 | For latest stable version, pleace switch to `release` branch.
35 |
36 | Since 1.6 we will move to Swift 3+. Please make sure you compile with Xcode >= 8.1.
37 |
38 | ## TODO
39 |
40 | - [ ] migrate to CocoaPods instead of git submodules
41 | - [ ] migrate to swift (Anakin is working on this)
42 |
43 | ## Maintainers
44 |
45 | Currently, this project is mainly maintained by:
46 |
47 | 1. [Chase Zhang](github.com/shanzi)
48 | 2. [Anakin(Yancheng) Zheng](https://github.com/AnakinMac)
49 |
50 | More developers are wanted!
51 |
52 | # LICENSE
53 |
54 | Main code of this project is licensed under GPLv3. For more details refer to [LICENSE](./LICENSE).
55 | All codes under [extern](./extern) are external dependencies and are still licensed under their original licenses.
56 |
--------------------------------------------------------------------------------
/diumoo/DMApp.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMApp.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-7.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface DMApp : NSApplication
13 | {
14 | NSString *openedURLString;
15 | }
16 |
17 | @property (copy) NSString *openedURLString;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/diumoo/DMApp.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMApp.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-7.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMApp.h"
10 | #import "DMService.h"
11 | #import "SPMediaKeyTap.h"
12 |
13 | @implementation DMApp
14 |
15 | @synthesize openedURLString;
16 |
17 | -(id) init
18 | {
19 | self = [super init];
20 | if(self)
21 | {
22 | NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
23 | LSSetDefaultHandlerForURLScheme((CFStringRef)@"diumoo", (__bridge CFStringRef)bundleID);
24 |
25 | [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
26 | andSelector:@selector(handleEvent:withReplyEvent:)
27 | forEventClass:kInternetEventClass
28 | andEventID:kAEGetURL];
29 | }
30 | return self;
31 | }
32 |
33 |
34 | - (void)handleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
35 | {
36 | NSString* urlstring = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
37 | openedURLString = [urlstring copy];
38 | [DMService openDiumooLink:openedURLString];
39 | }
40 |
41 | - (void)sendEvent:(NSEvent *)theEvent
42 | {
43 | // If event tap is not installed, handle events that reach the app instead
44 | BOOL shouldHandleMediaKeyEventLocally = ![SPMediaKeyTap usesGlobalMediaKeyTap];
45 |
46 | if(shouldHandleMediaKeyEventLocally && [theEvent type] == NSSystemDefined && [theEvent subtype] == SPSystemDefinedEventMediaKeys) {
47 | [(id)[self delegate] mediaKeyTap:nil receivedMediaKeyEvent:theEvent];
48 | }
49 | [super sendEvent:theEvent];
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/diumoo/DMAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMAppDelegate.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-7.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "DMControlCenter.h"
12 | #import "DMPanelWindowController.h"
13 | #import "DMShortcutsHandler.h"
14 | #import "PLTabPreferenceControl.h"
15 | #import "SPMediaKeyTap.h"
16 |
17 | @interface DMAppDelegate : NSObject {
18 | DMControlCenter* center;
19 | SPMediaKeyTap* mediakeyTap;
20 | }
21 |
22 | - (IBAction)showPreference:(id)sender;
23 | - (IBAction)importOrExport:(id)sender;
24 | - (IBAction)showHelp:(id)sender;
25 | - (void)keyShortcuts:(id)key;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/DMDocument.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMDocument.h
3 | // documentTest
4 | //
5 | // Created by Shanzi on 12-6-25.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DMDocument : NSDocument {
12 | NSString* sid;
13 | NSString* ssid;
14 | NSString* aid;
15 |
16 | NSDictionary* baseSongInfo;
17 | }
18 |
19 | @property (readonly) NSDictionary* baseSongInfo;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/DMDocument.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMDocument.m
3 | // documentTest
4 | //
5 | // Created by Shanzi on 12-6-25.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMDocument.h"
10 | #import "DMDocumentWindowController.h"
11 | #import "DMPlayRecordHandler.h"
12 | #import "DMService.h"
13 |
14 | @implementation DMDocument
15 | @synthesize baseSongInfo;
16 |
17 | - (id)init
18 | {
19 | if (self = [super init]) {
20 | // Add your subclass-specific initialization here.
21 | }
22 | return self;
23 | }
24 |
25 | - (void)makeWindowControllers
26 | {
27 | if (sid == nil)
28 | return;
29 | if ([self.windowControllers count] == 0) {
30 | DMDocumentWindowController* windowController = [[DMDocumentWindowController allocWithZone:nil] init];
31 | [self addWindowController:windowController];
32 | }
33 | }
34 |
35 | - (void)revertDocumentToSaved:(id)sender
36 | {
37 | if ([self respondsToSelector:@selector(browseDocumentVersions:)]) {
38 | [super browseDocumentVersions:self];
39 | }
40 | else {
41 | [super revertDocumentToSaved:self];
42 | }
43 | }
44 |
45 | - (BOOL)revertToContentsOfURL:(NSURL*)url ofType:(NSString*)typeName error:(NSError**)outError
46 | {
47 | BOOL success = [super revertToContentsOfURL:url ofType:typeName error:outError];
48 | if (success) {
49 | [[self windowControllers] makeObjectsPerformSelector:@selector(setupWindowForDocument:) withObject:self];
50 | [[DMPlayRecordHandler sharedRecordHandler] removeCurrentVersion];
51 | [[DMPlayRecordHandler sharedRecordHandler] playSongWith:sid andSsid:ssid];
52 | }
53 | return YES;
54 | }
55 |
56 | + (BOOL)autosavesInPlace
57 | {
58 | return YES;
59 | }
60 |
61 | + (BOOL)preservesVersions
62 | {
63 | return YES;
64 | }
65 |
66 | - (BOOL)hasUnautosavedChanges
67 | {
68 | return NO;
69 | }
70 |
71 | - (NSData*)dataOfType:(NSString*)typeName error:(NSError**)outError
72 | {
73 | NSData* data = [[baseSongInfo descriptionWithLocale:nil] dataUsingEncoding:NSUTF8StringEncoding];
74 | return data;
75 | }
76 |
77 | - (BOOL)readFromURL:(NSURL*)url ofType:(NSString*)type error:(NSError**)outError
78 | {
79 | if ([type isEqualToString:@"_private_record"]) {
80 | NSString* _sid = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
81 | if (_sid) {
82 | DMPlayRecordHandler* sharedHandler = [DMPlayRecordHandler sharedRecordHandler];
83 | NSManagedObject* object = [sharedHandler songWithSid:_sid];
84 | if (object) {
85 | sid = [object valueForKey:@"sid"];
86 | ssid = [object valueForKey:@"ssid"];
87 | aid = [object valueForKey:@"aid"];
88 |
89 | NSArray* keyarray = [[[object entity] attributesByName] allKeys];
90 | NSDictionary* infodict = [object dictionaryWithValuesForKeys:keyarray];
91 | baseSongInfo = infodict;
92 | return YES;
93 | }
94 | }
95 | }
96 | else if ([type isEqualToString:@"shortcut"]) {
97 | NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:url];
98 | if (dict) {
99 | sid = [dict valueForKey:@"sid"];
100 | ssid = [dict valueForKey:@"ssid"];
101 | aid = [dict valueForKey:@"aid"];
102 | baseSongInfo = dict;
103 | if (sid) {
104 | return YES;
105 | }
106 | }
107 | }
108 | else if ([type isEqualToString:@"Play Record"]) {
109 | if (NSAlertDefaultReturn
110 | == NSRunAlertPanel(NSLocalizedString(@"IMPORT_PLAY_RECORD", nil),
111 | NSLocalizedString(@"IMPORT_PLAY_RECORD_DETAIL", nil),
112 | //@"您刚刚打开的一个diumoo播放记录文件,是否导入这些记录?",
113 | NSLocalizedString(@"YES", nil), NSLocalizedString(@"NO", nil), nil)) {
114 | [DMService importRecordOperationWithFilePath:url];
115 | }
116 |
117 | return YES;
118 | }
119 |
120 | if (outError != nil) {
121 | *outError = [NSError errorWithDomain:NSLocalizedString(@"OPEN_FILE_FAILED", nil) code:-1 userInfo:nil];
122 | }
123 |
124 | return NO;
125 | }
126 |
127 | @end
128 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/DMDocumentWindowController/DMDetailViewController/DMDetailViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMDetailViewController.h
3 | // documentTest
4 | //
5 | // Created by Shanzi on 12-7-2.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "JUInspectorViewContainer.h"
10 | #import
11 |
12 | @interface DMDetailViewController : JUInspectorViewContainer {
13 | NSDictionary* baseInfoDict;
14 | NSArray* baseInfoKeys;
15 | NSArray* songsArray;
16 | }
17 |
18 | @property (nonatomic, strong) NSTableView* baseInformationView;
19 | @property (nonatomic, strong) NSTextView* summaryView;
20 | @property (nonatomic, strong) NSTableView* songsView;
21 |
22 | - (id)initWithBaseInformation:(NSDictionary*)info summary:(NSString*)summary andSongs:(NSArray*)songs;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/DMDocumentWindowController/DMDetailViewController/DMDetailViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMDetailViewController.m
3 | // documentTest
4 | //
5 | // Created by Shanzi on 12-7-2.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMDetailViewController.h"
10 | #import "JUInspectorView.h"
11 |
12 | #define kColumnKey @"k"
13 | #define kColumnValue @"v"
14 |
15 | @interface DMDetailViewController ()
16 |
17 | @end
18 |
19 | @implementation DMDetailViewController
20 | @synthesize baseInformationView, summaryView, songsView;
21 |
22 | - (id)initWithBaseInformation:(NSDictionary*)info summary:(NSString*)summary andSongs:(NSArray*)songs
23 | {
24 | self = [super init];
25 | if (self) {
26 | // Initialization code here
27 |
28 | baseInfoKeys = @[
29 | NSLocalizedString(@"DETAIL_ALBUM", @"专辑名"),
30 | NSLocalizedString(@"DETAIL_SINGER", @"艺术家"),
31 | NSLocalizedString(@"DETAIL_DOUBAN_RATING", @"豆瓣评分"),
32 | NSLocalizedString(@"DETAIL_VERSION", @"版本特性"),
33 | NSLocalizedString(@"DETAIL_PUBLISHER", @"出版者"),
34 | NSLocalizedString(@"DETAIL_PUBDATE", @"发行时间"),
35 | NSLocalizedString(@"DETAIL_MEDIA", @"介质"),
36 | NSLocalizedString(@"DETAIL_DISCS", @"唱片数"),
37 | NSLocalizedString(@"DETAIL_EAN", @"条形码")
38 | ];
39 |
40 | self.baseInformationView = [self buildTableView];
41 | self.songsView = [self buildTableView];
42 |
43 | self.summaryView = [[NSTextView alloc]
44 | initWithFrame:NSMakeRect(0, 0, 400, 200)];
45 | [summaryView setEditable:NO];
46 | [summaryView setAutoresizingMask:NSViewWidthSizable];
47 |
48 | if (summary) {
49 | self.summaryView.string = summary;
50 | }
51 | else {
52 | self.summaryView.string = NSLocalizedString(@"DETAIL_UNKNOWN", nil);
53 | }
54 |
55 | baseInfoDict = info;
56 | songsArray = songs;
57 |
58 | JUInspectorView* infoInspector = [[JUInspectorView alloc] init];
59 | infoInspector.name = NSLocalizedString(@"DETAIL_ALBUM_INFO", @"专辑信息");
60 | infoInspector.body = baseInformationView;
61 |
62 | JUInspectorView* summaryInspector = [[JUInspectorView alloc] init];
63 | NSScrollView* scrollView = [[NSScrollView alloc]
64 | initWithFrame:NSMakeRect(0, 0, 400, 200)];
65 |
66 | [scrollView setDocumentView:summaryView];
67 | [scrollView setHasVerticalScroller:YES];
68 | [scrollView setAutohidesScrollers:YES];
69 |
70 | summaryInspector.name = NSLocalizedString(@"DETAIL_ABSTRACT", @"简介");
71 | summaryInspector.body = scrollView;
72 |
73 | JUInspectorView* songsInspector = [[JUInspectorView alloc] init];
74 | songsInspector.name = NSLocalizedString(@"DETAIL_SONGS", @"曲目");
75 | songsInspector.body = songsView;
76 |
77 | [self addInspectorView:infoInspector expanded:YES];
78 | [self addInspectorView:summaryInspector expanded:NO];
79 | [self addInspectorView:songsInspector expanded:YES];
80 | }
81 | return self;
82 | }
83 |
84 | - (NSTableView*)buildTableView
85 | {
86 | NSTableView* tableview = [[NSTableView alloc] init];
87 | NSTableColumn* column1 = [[NSTableColumn alloc] initWithIdentifier:kColumnKey];
88 | NSTableColumn* column2 = [[NSTableColumn alloc] initWithIdentifier:kColumnValue];
89 | [tableview addTableColumn:column1];
90 | [tableview addTableColumn:column2];
91 | [tableview setDelegate:self];
92 | [tableview setDataSource:self];
93 |
94 | return tableview;
95 | }
96 |
97 | - (BOOL)tableView:(NSTableView*)tableView shouldEditTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
98 | {
99 | return NO;
100 | }
101 |
102 | - (BOOL)tableView:(NSTableView*)tableView shouldSelectRow:(NSInteger)row
103 | {
104 | return NO;
105 | }
106 |
107 | - (BOOL)tableView:(NSTableView*)tableView shouldSelectTableColumn:(NSTableColumn*)tableColumn
108 | {
109 | return NO;
110 | }
111 |
112 | - (BOOL)tabView:(NSTabView*)tableView shouldSelectTabViewItem:(NSTabViewItem*)tabViewItem
113 | {
114 | return YES;
115 | }
116 |
117 | - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
118 | {
119 | if (tableView == songsView) {
120 | return [songsArray count];
121 | }
122 | else {
123 | return [baseInfoKeys count];
124 | ;
125 | }
126 | }
127 |
128 | - (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
129 | {
130 | if (tableView == songsView) {
131 | if ([tableColumn.identifier isEqualToString:kColumnKey]) {
132 | return [NSString stringWithFormat:@"%ld", row + 1];
133 | }
134 | else {
135 | return songsArray[row];
136 | }
137 | }
138 | else {
139 | if ([tableColumn.identifier isEqualToString:kColumnKey]) {
140 |
141 | return baseInfoKeys[row];
142 | }
143 | else {
144 |
145 | NSString* string = [baseInfoDict valueForKey:baseInfoKeys[row]];
146 | if (string == nil) {
147 | return NSLocalizedString(@"DETAIL_UNKNOWN", @"未知");
148 | }
149 | else {
150 | return string;
151 | }
152 | }
153 | }
154 | }
155 |
156 | @end
157 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/DMDocumentWindowController/DMDocumentWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMDocumentWindowController.h
3 | // documentTest
4 | //
5 | // Created by Shanzi on 12-7-1.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | @class SMTabBar;
11 |
12 | @interface DMDocumentWindowController : NSWindowController {
13 |
14 | IBOutlet SMTabBar* tabBar;
15 | IBOutlet NSTabView* tabView;
16 |
17 | // -------------------------预览标签页--------------------------
18 | IBOutlet NSButton* revertButton;
19 | IBOutlet NSButton* albumCoverButton;
20 | IBOutlet NSTextField* songTitle;
21 | IBOutlet NSTextField* artist;
22 |
23 | // ------------------------详细信息标签页------------------------
24 | IBOutlet NSTextField* indicatorText;
25 | IBOutlet NSProgressIndicator* progressIndicator;
26 |
27 | // -----------------------其他---------------------------------
28 | NSString* albumTitle;
29 | NSString* aid;
30 | NSString* albumLocation;
31 |
32 | NSLock* lock;
33 | }
34 |
35 | - (id)init;
36 |
37 | - (void)setupWindowForDocument:(NSDocument*)doc;
38 |
39 | - (IBAction)revert:(id)sender;
40 | - (IBAction)playAlbum:(id)sender;
41 | - (IBAction)openAlbumLocation:(id)sender;
42 | @end
43 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorBaseView.h:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectorBaseView.h
3 | // JUInspectorView
4 | //
5 | // Created by Jon Gilkison on 9/28/11.
6 | // Copyright 2011 Interfacelab LLC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface JUInspectorBaseView : NSView {
13 | }
14 |
15 | -(void)setupView;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorBaseView.m:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectorBaseView.m
3 | // JUInspectorView
4 | //
5 | // Created by Jon Gilkison on 9/28/11.
6 | // Copyright 2011 Interfacelab LLC. All rights reserved.
7 | //
8 |
9 | #import "JUInspectorBaseView.h"
10 |
11 |
12 | @implementation JUInspectorBaseView
13 |
14 | #pragma mark - Init/Dealloc
15 |
16 | - (id)initWithFrame:(NSRect)frame
17 | {
18 | if((self = [super initWithFrame:frame]))
19 | {
20 | [self setupView];
21 | }
22 |
23 | return self;
24 | }
25 |
26 | - (id)initWithCoder:(NSCoder *)decoder
27 | {
28 | if((self = [super initWithCoder:decoder]))
29 | {
30 | [self setupView];
31 | }
32 |
33 | return self;
34 | }
35 |
36 | - (void)setupView
37 | {
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorView.h:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectoView.h
3 | // JUInspectorView
4 | //
5 | // Copyright (c) 2011 by Sidney Just
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9 | // and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
13 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
14 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 | //
17 |
18 | #import
19 | #import "JUInspectorBaseView.h"
20 | #import "JUInspectorViewHeader.h"
21 | #import "JUInspectorViewContainer.h"
22 |
23 | @interface JUInspectorView : JUInspectorBaseView
24 | {
25 | BOOL expanded;
26 |
27 | NSInteger index;
28 | NSView *body;
29 |
30 | JUInspectorViewHeader *header;
31 | JUInspectorViewContainer *container;
32 | }
33 |
34 | @property (assign, nonatomic) NSString *name;
35 | @property (assign, nonatomic) NSInteger index;
36 |
37 | @property (retain, nonatomic) IBOutlet NSView *body;
38 | @property (assign, nonatomic) BOOL expanded;
39 |
40 | @property (assign, nonatomic) JUInspectorViewContainer *container;
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorView.m:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectoView.m
3 | // JUInspectorView
4 | //
5 | // Copyright (c) 2011 by Sidney Just
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9 | // and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
13 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
14 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 | //
17 |
18 | #import "JUInspectorView.h"
19 |
20 | @implementation JUInspectorView
21 |
22 | @synthesize name, index, body, expanded, container;
23 |
24 | #pragma mark - Init/Dealloc
25 |
26 | - (void)setupView
27 | {
28 | header = [[JUInspectorViewHeader alloc] initWithFrame:NSZeroRect];
29 | [header setAutoresizingMask:NSViewWidthSizable];
30 | header.delegate=self;
31 |
32 | [self addSubview:header];
33 | [self setExpanded:YES];
34 | }
35 |
36 | - (void)dealloc
37 | {
38 | [header release];
39 | [body release];
40 |
41 | [super dealloc];
42 | }
43 |
44 | #pragma mark - Properties
45 |
46 | - (void)setExpanded:(BOOL)value
47 | {
48 | if (expanded==value)
49 | return;
50 |
51 | expanded=value;
52 |
53 | NSRect frame;
54 |
55 | if (expanded)
56 | {
57 | frame = [body bounds];
58 | frame.origin = [self frame].origin;
59 | frame.size.height += [header bounds].size.height;
60 |
61 | [body setHidden:NO];
62 | [header setState:NSOnState];
63 | [container arrangeViews];
64 | }
65 | else
66 | {
67 | frame.origin = [self frame].origin;
68 | frame.size = [header frame].size;
69 |
70 | [body setHidden:YES];
71 | [header setState:NSOffState];
72 | }
73 |
74 | [self setFrame:frame];
75 | [container arrangeViews];
76 | }
77 |
78 | -(NSString *)name
79 | {
80 | return [header title];
81 | }
82 |
83 | - (void)setName:(NSString *)value
84 | {
85 | [header setTitle:value];
86 | }
87 |
88 | - (void)setBody:(NSView *)pbody
89 | {
90 | [body removeFromSuperview];
91 | [body release];
92 |
93 | body = [pbody retain];
94 |
95 | if([body isFlipped])
96 | {
97 | NSRect bodyFrame = [body bounds];
98 | bodyFrame.origin.y = [header bounds].size.height + 1.0;
99 |
100 | [body setFrame:bodyFrame];
101 | }
102 | else
103 | {
104 | NSRect bodyFrame = [body bounds];
105 | bodyFrame.origin.y = -bodyFrame.size.height + [header bounds].size.height;
106 |
107 | [body setFrame:bodyFrame];
108 | }
109 |
110 | [self addSubview:body];
111 |
112 | self.expanded = !expanded;
113 | }
114 |
115 | #pragma mark - NSView Overrides
116 |
117 | - (void)setFrame:(NSRect)frameRect
118 | {
119 | [super setFrame:frameRect];
120 |
121 | NSRect bodyRect = [body frame];
122 | bodyRect.size.width = frameRect.size.width;
123 | [body setFrame:bodyRect];
124 | }
125 |
126 | - (BOOL)isFlipped
127 | {
128 | return YES;
129 | }
130 |
131 | - (void)drawRect:(NSRect)dirtyRect
132 | {
133 | if(expanded)
134 | {
135 | [[header dashColor] set];
136 |
137 | NSRect dashRect = [self bounds];
138 | dashRect.origin.x -= 1.0;
139 | dashRect.size.width += 2.0;
140 |
141 | NSBezierPath *path = [NSBezierPath bezierPathWithRect:dashRect];
142 | [path setLineWidth:1.0];
143 | [path stroke];
144 | }
145 | }
146 |
147 | - (NSString *)description
148 | {
149 | return [NSString stringWithFormat:@"JUCollectionView \"%@\", expanded: %@", self.name, expanded ? @"YES" : @"NO"];
150 | }
151 |
152 | - (NSComparisonResult)compare:(JUInspectorView *)otherView
153 | {
154 | if(otherView.index > index)
155 | return NSOrderedDescending;
156 |
157 | if(otherView.index < index)
158 | return NSOrderedAscending;
159 |
160 | return NSOrderedSame;
161 | }
162 |
163 | #pragma mark - JUInspectorViewHeaderDelegate
164 |
165 | -(void)headerClicked:(JUInspectorViewHeader *)headerView
166 | {
167 | self.expanded=!expanded;
168 | }
169 |
170 |
171 | @end
172 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorViewContainer.h:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectorViewContainer.h
3 | // JUInspectorView
4 | //
5 | // Copyright (c) 2011 by Sidney Just
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9 | // and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
13 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
14 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 | //
17 |
18 | #import
19 | #import "JUInspectorBaseView.h"
20 |
21 | @class JUInspectorView;
22 |
23 | @interface JUInspectorViewContainer : JUInspectorBaseView
24 | {
25 | NSMutableArray *inspectorViews;
26 | }
27 |
28 | - (void)arrangeViews;
29 |
30 | - (void)addInspectorView:(JUInspectorView *)view expanded:(BOOL)expanded;
31 | - (void)addInspectorView:(JUInspectorView *)view atIndex:(NSInteger)index expanded:(BOOL)expanded;
32 | - (void)removeInspectorView:(JUInspectorView *)view;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorViewContainer.m:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectorViewContainer.m
3 | // JUInspectorView
4 | //
5 | // Copyright (c) 2011 by Sidney Just
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9 | // and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
13 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
14 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 | //
17 |
18 | #import "JUInspectorViewContainer.h"
19 | #import "JUInspectorView.h"
20 |
21 | @interface JUInspectorView (JUInspectorViewPrivate)
22 |
23 | -(void)updateBounds;
24 |
25 | @end
26 |
27 | @implementation JUInspectorViewContainer
28 |
29 | #pragma mark - Init/Dealloc
30 |
31 | - (void)setupView
32 | {
33 | inspectorViews = [[NSMutableArray alloc] init];
34 | }
35 |
36 | - (void)dealloc
37 | {
38 | [inspectorViews release];
39 | [super dealloc];
40 | }
41 |
42 | #pragma mark - NSView override
43 |
44 | - (void)setFrame:(NSRect)frameRect
45 | {
46 | [super setFrame:frameRect];
47 | [self arrangeViews];
48 | }
49 |
50 | - (BOOL)isFlipped
51 | {
52 | return YES;
53 | }
54 |
55 |
56 | #pragma mark - Private methods
57 |
58 | - (void)updateBounds
59 | {
60 | CGFloat height = 0.0;
61 | for(JUInspectorView *view in inspectorViews)
62 | {
63 | height += [view frame].size.height;
64 | }
65 |
66 | NSRect frame;
67 | frame.origin = [self frame].origin;
68 | frame.size.width = [self bounds].size.width;
69 | frame.size.height = height;
70 |
71 | NSClipView *clipView = [[self enclosingScrollView] contentView];
72 | if(clipView)
73 | {
74 | frame.size.width = [clipView documentRect].size.width;
75 | }
76 |
77 | [super setFrame:frame];
78 | }
79 |
80 | - (void)arrangeViews
81 | {
82 | NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"index" ascending:YES];
83 | [inspectorViews sortUsingDescriptors:@[sortDescriptor]];
84 | [self updateBounds];
85 |
86 |
87 | BOOL collapsed = NO;
88 | NSRect frame = NSMakeRect(0.0, 0.0, [self bounds].size.width, 0.0);
89 |
90 | for(JUInspectorView *view in inspectorViews)
91 | {
92 | if(collapsed)
93 | frame.origin.y -= 1.0;
94 |
95 | frame.size.height = [view frame].size.height;
96 |
97 | [view setFrame:frame];
98 |
99 | frame.origin.y += frame.size.height;
100 | collapsed = !view.expanded;
101 | }
102 | }
103 |
104 |
105 | #pragma mark - Add/Remove Inspectors
106 |
107 | - (void)addInspectorView:(JUInspectorView *)view expanded:(BOOL)expanded
108 | {
109 | if(![inspectorViews containsObject:view])
110 | {
111 | [view setContainer:self];
112 |
113 | [inspectorViews addObject:view];
114 | [self addSubview:view];
115 | [self arrangeViews];
116 |
117 | view.expanded=expanded;
118 | }
119 | }
120 |
121 | - (void)addInspectorView:(JUInspectorView *)view atIndex:(NSInteger)index expanded:(BOOL)expanded
122 | {
123 | [view setIndex:index];
124 | [self addInspectorView:view expanded:expanded];
125 | }
126 |
127 | - (void)removeInspectorView:(JUInspectorView *)view
128 | {
129 | if([inspectorViews containsObject:view])
130 | {
131 | [view setContainer:self];
132 |
133 | [inspectorViews removeObject:view];
134 | [view removeFromSuperview];
135 | [self arrangeViews];
136 | }
137 | }
138 |
139 |
140 |
141 | @end
142 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorViewHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectorView.h
3 | // JUInspectorView
4 | //
5 | // Copyright (c) 2011 by Sidney Just
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9 | // and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
13 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
14 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 | //
17 |
18 | #import
19 | #import "JUInspectorBaseView.h"
20 |
21 | @class JUInspectorViewHeader;
22 |
23 | @protocol JUInspectorViewHeaderDelegate
24 |
25 | -(void)headerClicked:(JUInspectorViewHeader *)headerView;
26 |
27 | @end
28 |
29 | @interface JUInspectorViewHeader : JUInspectorBaseView
30 | {
31 | id delegate;
32 |
33 | NSButton *disclosureTriangle;
34 | NSTextField *nameField;
35 |
36 | NSColor *dashColor;
37 | NSColor *gradientStartColor;
38 | NSColor *gradientEndColor;
39 | }
40 |
41 | @property (assign, nonatomic) id delegate;
42 |
43 | @property (readonly) NSButton *disclosureTriangle;
44 |
45 | @property (retain, nonatomic) NSColor *dashColor;
46 | @property (retain, nonatomic) NSColor *gradientStartColor;
47 | @property (retain, nonatomic) NSColor *gradientEndColor;
48 |
49 | @property (assign, nonatomic) NSInteger state;
50 | @property (assign, nonatomic) NSString *title;
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/diumoo/DMDocument/JUInspectorView/JUInspectorViewHeader.m:
--------------------------------------------------------------------------------
1 | //
2 | // JUInspectorView.m
3 | // JUInspectorView
4 | //
5 | // Copyright (c) 2011 by Sidney Just
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9 | // and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
13 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
14 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 | //
17 |
18 | #import "JUInspectorViewHeader.h"
19 |
20 | @interface JUInspectorViewHeader(Private)
21 |
22 | -(void)setupView;
23 | -(void)disclosureClicked:(id)sender;
24 |
25 | @end
26 |
27 | @implementation JUInspectorViewHeader
28 |
29 | @synthesize dashColor, gradientStartColor, gradientEndColor, disclosureTriangle, state, title, delegate;
30 |
31 | #pragma mark - Init/Dealloc
32 |
33 | - (id)initWithCoder:(NSCoder *)decoder
34 | {
35 | return [self initWithFrame:NSZeroRect];
36 | }
37 |
38 | - (id)initWithFrame:(NSRect)frame
39 | {
40 | if((self = [super initWithFrame:NSMakeRect(0.0, 0.0, 222.0, 20.0)]))
41 | {
42 | }
43 |
44 | return self;
45 | }
46 |
47 |
48 | - (void)setupView
49 | {
50 | dashColor = [[NSColor colorWithCalibratedRed:0.502 green:0.502 blue:0.502 alpha:1.0] retain];
51 | gradientStartColor = [[NSColor colorWithCalibratedRed:0.922 green:0.925 blue:0.976 alpha:1.0] retain];
52 | gradientEndColor = [[NSColor colorWithCalibratedRed:0.741 green:0.749 blue:0.831 alpha:1.0] retain];
53 |
54 | disclosureTriangle = [[NSButton alloc] initWithFrame:NSMakeRect(5.0, 4.0, 13.0, 13.0)];
55 | [disclosureTriangle setBezelStyle:NSDisclosureBezelStyle];
56 | [disclosureTriangle setButtonType: NSPushOnPushOffButton];
57 | [disclosureTriangle setTitle:nil];
58 | [disclosureTriangle highlight:NO];
59 | [disclosureTriangle setTarget:self];
60 | [disclosureTriangle setAction:@selector(disclosureClicked:)];
61 |
62 | nameField = [[NSTextField alloc] initWithFrame:NSMakeRect(20.0, 4.0, [self bounds].size.width - 8.0, 15.0)];
63 | [nameField setEditable:NO];
64 | [nameField setBackgroundColor:[NSColor clearColor]];
65 | [nameField setBezeled:NO];
66 | [nameField setFont:[NSFont boldSystemFontOfSize:12.0]];
67 | [nameField setTextColor:[NSColor colorWithCalibratedRed:0.220 green:0.224 blue:0.231 alpha:1.0]];
68 |
69 |
70 | [self addSubview:disclosureTriangle];
71 | [self addSubview:nameField];
72 | }
73 |
74 | - (void)dealloc
75 | {
76 | [dashColor release];
77 | [gradientEndColor release];
78 | [gradientStartColor release];
79 | [disclosureTriangle release];
80 | [nameField release];
81 |
82 | [super dealloc];
83 | }
84 |
85 | #pragma mark - Properties
86 |
87 | -(NSInteger)state
88 | {
89 | return [disclosureTriangle state];
90 | }
91 |
92 | - (void)setState:(NSInteger)value
93 | {
94 | [disclosureTriangle setState:value];
95 | }
96 |
97 | -(NSString *)title
98 | {
99 | return [nameField stringValue];
100 | }
101 |
102 | - (void)setTitle:(NSString *)value
103 | {
104 | [nameField setStringValue:value];
105 | }
106 |
107 | #pragma mark - Drawing
108 |
109 | - (void)drawRect:(NSRect)dirtyRect
110 | {
111 | NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:gradientStartColor endingColor:gradientEndColor];
112 | [gradient drawInRect:[self bounds] angle:-90.0];
113 | [gradient autorelease];
114 |
115 | [dashColor set];
116 |
117 | NSRect dashRect = [self bounds];
118 | dashRect.origin.x -= 1.0;
119 | dashRect.size.width += 2.0;
120 |
121 | NSBezierPath *path = [NSBezierPath bezierPathWithRect:dashRect];
122 | [path setLineWidth:1.0];
123 | [path stroke];
124 | }
125 |
126 | #pragma mark - Event handling
127 |
128 | - (void)mouseUp:(NSEvent *)theEvent
129 | {
130 | [delegate headerClicked:self];
131 | }
132 |
133 |
134 | -(void)disclosureClicked:(id)sender
135 | {
136 | [delegate headerClicked:self];
137 | }
138 |
139 | @end
140 |
--------------------------------------------------------------------------------
/diumoo/core/DMControlCenter/DMControlCenter.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMControlCenter.h
3 | // diumoo-core
4 | //
5 | // Created by Shanzi on 12-6-3.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #define kPauseOperationTypePass @"pass"
10 | #define kPauseOperationTypeSkip @"skip"
11 | #define kPauseOperationTypeFetchNewPlaylist @"newplaylist"
12 | #define kPauseOperationTypePlaySpecial @"special"
13 |
14 | #define kTimerPulseTypePlay @"kTimerPulseTypePlay"
15 | #define kTimerPulseTypePause @"kTimerPulseTypePause"
16 | #define KTimerPulseTypeVolumeChange @"kTimerPulseTypeVolumeChange"
17 |
18 | #import
19 | #import
20 | #import
21 |
22 | #import "diumoo-Swift.h"
23 | #import "DMPanelWindowController.h"
24 | #import "DMPlayRecordHandler.h"
25 | #import "NSDictionary+UrlEncoding.h"
26 | #import "DMService.h"
27 | #import "DMSearchPanelController.h"
28 |
29 | #define TIMER_INTERVAL 0.1
30 |
31 |
32 | typedef enum{
33 | PAUSE_PASS = 0,
34 | PAUSE_PAUSE,
35 | PAUSE_SKIP,
36 | PAUSE_NEW_PLAYLIST,
37 | PAUSE_SPECIAL,
38 | PAUSE_EXIT,
39 | } PAUSE_OPERATION_TYPE;
40 |
41 | @interface DMControlCenter : NSObject
42 | {
43 | NSString *channel;
44 |
45 | DMPlayableItem *__strong playingItem;
46 | DMPlayableItem *__strong waitingItem;
47 | DMPlaylistFetcher *fetcher;
48 |
49 | DMNotificationCenter *notificationCenter;
50 | DMPanelWindowController *diumooPanel;
51 | DMPlayRecordHandler *recordHandler;
52 |
53 | BOOL canPlaySpecial;
54 | }
55 |
56 | @property (strong) DMPlayableItem *playingItem;
57 | @property (strong) DMPlayableItem *waitingItem;
58 | @property DMPanelWindowController *diumooPanel;
59 |
60 | //self methods
61 | -(void) fireToPlayDefault;
62 | -(void) stopForExit;
63 | -(void) qualityChanged;
64 | -(void) volumeChange:(float)volume;
65 |
66 | //methods in DMPlayableItemDelegate
67 | - (void)playableItem:(DMPlayableItem * )item logStateChanged:(NSInteger)logStateChanged;
68 | @end
69 |
--------------------------------------------------------------------------------
/diumoo/core/DMErrorLog/DMErrorLog.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMErrorLog.h
3 | // diumoo
4 | //
5 | // Created by AnakinGWY on 12-8-10.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface DMErrorLog : NSObject
12 | +(id) sharedErrorLog;
13 | +(void) logErrorWith:(id)object method:(SEL)methodName andError:(NSError*)error;
14 | +(void) logStateWith:(id)object fromMethod:(SEL)methodName andString:(NSString*)aString;
15 | @end
16 |
--------------------------------------------------------------------------------
/diumoo/core/DMErrorLog/DMErrorLog.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMErrorLog.m
3 | // diumoo
4 | //
5 | // Created by AnakinGWY on 12-8-10.
6 | //
7 | //
8 |
9 | #import "DMErrorLog.h"
10 |
11 | static DMErrorLog *sharedErrorLogger;
12 |
13 | @implementation DMErrorLog
14 |
15 | +(id) sharedErrorLog
16 | {
17 | if ([[[NSUserDefaults standardUserDefaults] valueForKey:@"enableLog"] integerValue] == NSOnState) {
18 | sharedErrorLogger = [[DMErrorLog alloc] init];
19 | } else
20 | sharedErrorLogger = nil;
21 |
22 | return sharedErrorLogger;
23 | }
24 |
25 | +(void) logErrorWith:(id)object method:(SEL)methodName andError:(NSError *)error
26 | {
27 | if (sharedErrorLogger != nil) {
28 | NSLog(@"ERROR Log: %@ %@ returns an Error = %@",object,NSStringFromSelector(methodName),error);
29 | }
30 | }
31 |
32 | +(void) logStateWith:(id)object fromMethod:(SEL)methodName andString:(NSString *)aString
33 | {
34 | if (sharedErrorLogger != nil) {
35 | NSLog(@"State Log: %@ %@ has a state = %@",object,NSStringFromSelector(methodName),aString);
36 | }
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/diumoo/core/DMNotificationCenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DMNotificationCenter.swift
3 | // diumoo
4 | //
5 | // Created by Yancheng Zheng on 6/18/16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import AppKit
11 |
12 | public class DMNotificationCenter : NSObject, NSUserNotificationCenterDelegate {
13 |
14 | internal let pref = UserDefaults.standard
15 | internal let NCCenter = NSUserNotificationCenter.default
16 | internal let needToUpdateDock : Bool
17 |
18 | public func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool {
19 | return true
20 | }
21 |
22 | override init() {
23 | // Show Dock icon setting won't change without restart app, so it's safe to put it here
24 | // I'm not sure about how expensive this is
25 | needToUpdateDock = (Int(self.pref.value(forKey: "displayAlbumCoverOnDock") as! NSNumber) == NSOnState)
26 | super.init()
27 | NSUserNotificationCenter.default.delegate = self
28 | }
29 |
30 | deinit {
31 | NSUserNotificationCenter.default.delegate = nil
32 | }
33 |
34 | func isNotificationON() -> Bool {
35 | return Int(self.pref.value(forKey: "enableNotification") as! NSNumber) == NSOnState
36 | }
37 |
38 | public func notifyMusicPlayback(withItem item: DMPlayableItem) {
39 | if isNotificationON() {
40 | let detail = String("\(item.musicInfo["artist"]!) - <\(item.musicInfo["albumtitle"]!)>")
41 | let aNotification = NSUserNotification.init()
42 | aNotification.title = item.musicInfo["title"] as? String
43 | aNotification.informativeText = detail
44 | aNotification.contentImage = item.cover
45 | aNotification.soundName = nil
46 | self.NCCenter.deliver(aNotification)
47 | }
48 |
49 | if self.needToUpdateDock {
50 | let image = DockImageProvider.albumImage(from: item)
51 | NSApplication.shared().applicationIconImage = image
52 | }
53 | }
54 |
55 | public func notifyBitrate() {
56 | if isNotificationON() {
57 | let title = NSLocalizedString("BITRATE_CHANGED", comment: "Music bitrate changed.")
58 | var detail = NSLocalizedString("BITRATE_CHANGED_TO_VALUE", comment: "Music bitrate changed to.")
59 | let quality = pref.value(forKey: "musicQuality") as? Int
60 | detail.append(String("\(quality!) Kbps"))
61 |
62 | let aNotification = NSUserNotification.init()
63 | aNotification.title = title
64 | aNotification.informativeText = detail
65 | aNotification.soundName = nil
66 |
67 | self.NCCenter.deliver(aNotification)
68 |
69 | }
70 | }
71 |
72 | public func clearNotifications() {
73 | self.NCCenter.removeAllDeliveredNotifications()
74 | }
75 |
76 | public func copylinkNotification (URLStr: String) {
77 | if isNotificationON() {
78 | let title = NSLocalizedString("SHARE_LINK_TITLE", comment: "share link")
79 |
80 | let aNotification = NSUserNotification.init()
81 |
82 | aNotification.title = title
83 | aNotification.informativeText = URLStr
84 | aNotification.soundName = nil
85 |
86 | self.NCCenter.deliver(aNotification)
87 | }
88 |
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/diumoo/core/DMPlayRecordHandler/DMPlayRecordHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMPlayRecordHandler.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-7-2.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #define kPlaySongNotificationName @"playsong"
12 | #define kPlayAlbumNotificationName @"playalbum"
13 |
14 | @protocol DMPlayRecordHandlerDelegate
15 | -(void) playSongWithSid:(NSString*)sid andSsid:(NSString*)ssid;
16 | @end
17 |
18 | @class DMPlayableItem;
19 |
20 | @interface DMPlayRecordHandler : NSObject
21 | {
22 | NSURL *recordFileURL;
23 | NSManagedObjectContext *context;
24 | id delegate;
25 | }
26 | @property(nonatomic,copy) NSURL* recordFileURL;
27 | @property(nonatomic) NSManagedObjectContext* context;
28 | @property(nonatomic) id delegate;
29 |
30 | +(DMPlayRecordHandler*) sharedRecordHandler;
31 | -(NSManagedObject*) songWithSid:(NSString*) sid;
32 | -(NSManagedObject*) addRecordWithItem:(DMPlayableItem*) item;
33 | -(BOOL) addRecordWithDict:(NSDictionary*) dict;
34 | -(void) open;
35 | -(void) save;
36 | -(void) removeCurrentVersion;
37 | -(void) playSongWith:(NSString*)sid andSsid:(NSString*) ssid;
38 | -(NSArray*) allSongs;
39 | -(void) removeVersionsToLimit;
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/diumoo/core/DMPlayRecordHandler/DMPlayRecordHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMPlayRecordHandler.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-7-2.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMPlayRecordHandler.h"
10 | #import "diumoo-Swift.h"
11 | #import "DMService.h"
12 | #import "DMErrorLog.h"
13 |
14 | static DMPlayRecordHandler* recordHandler;
15 |
16 | @implementation DMPlayRecordHandler
17 | @synthesize recordFileURL,context,delegate;
18 |
19 | #pragma class methods
20 | +(DMPlayRecordHandler*) sharedRecordHandler
21 | {
22 | if (recordHandler==nil) {
23 | recordHandler = [[DMPlayRecordHandler alloc] init];
24 | }
25 | return recordHandler;
26 | }
27 |
28 | #pragma ---
29 |
30 | #pragma init and dealloc
31 | -(id) init
32 | {
33 | if (self = [super init]) {
34 | NSString* pathToFolder = [DMService pathToDataFileFolder];
35 | NSString* recordFilePath = [pathToFolder stringByAppendingPathComponent:@"record.dmsid"];
36 | recordFileURL = [NSURL fileURLWithPath:recordFilePath];
37 | context = [self makeContextWithPath:pathToFolder];
38 | }
39 | return self;
40 | }
41 |
42 | #pragma ---
43 |
44 | #pragma private methods
45 | -(NSManagedObjectContext*) makeContextWithPath:(NSString*) datapath
46 | {
47 | datapath = [datapath stringByAppendingPathComponent:@"dmdata.db"];
48 |
49 | NSManagedObjectModel* model = [NSManagedObjectModel mergedModelFromBundles:nil];
50 |
51 | NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc]
52 | initWithManagedObjectModel:model];
53 |
54 | NSError *error;
55 |
56 | [coordinator addPersistentStoreWithType:NSSQLiteStoreType
57 | configuration:nil
58 | URL:[NSURL fileURLWithPath:datapath]
59 | options:nil
60 | error:&error];
61 | if (error) {
62 | [DMErrorLog logErrorWith:self method:_cmd andError:error];
63 | [[NSFileManager defaultManager] removeItemAtPath:datapath error:nil];
64 | }
65 |
66 | context = [[NSManagedObjectContext alloc] initWithConcurrencyType:
67 | NSPrivateQueueConcurrencyType];
68 |
69 | [context setPersistentStoreCoordinator:coordinator];
70 |
71 | return context;
72 | }
73 | #pragma ---
74 |
75 |
76 | -(NSManagedObject*) songWithSid:(NSString*) sid
77 | {
78 |
79 | NSFetchRequest* fetchRequset = [NSFetchRequest fetchRequestWithEntityName:@"Song"];
80 | [fetchRequset setPredicate:[NSPredicate predicateWithFormat:@"sid = %@",sid]];
81 |
82 | NSError* fetchErr = nil;
83 | NSArray* results = [context executeFetchRequest:fetchRequset error:&fetchErr];
84 |
85 | if ([results count]>0) {
86 | // 找到了之前的记录
87 | return results[0];
88 | }
89 | return nil;
90 | }
91 |
92 | -(NSManagedObject*) addRecordWithItem:(DMPlayableItem *)item
93 | {
94 | if (item.musicInfo[@"ssid"] == nil) {
95 | return nil;
96 | }
97 |
98 | NSManagedObject* song = [self songWithSid:item.musicInfo[@"sid"]];
99 |
100 | if (song) {
101 | [song setValue:[NSDate date] forKey:@"date"];
102 | }
103 | else {
104 | // 没有找到之前的记录
105 | NSDate* date = [NSDate date];
106 |
107 | song = [NSEntityDescription insertNewObjectForEntityForName:@"Song"
108 | inManagedObjectContext:context];
109 | [song setValue:item.musicInfo[@"sid"] forKey:@"sid"];
110 | [song setValue:item.musicInfo[@"ssid"] forKey:@"ssid"];
111 | [song setValue:item.musicInfo[@"aid"] forKey:@"aid"];
112 | [song setValue:item.musicInfo[@"title"] forKey:@"title"];
113 | [song setValue:item.musicInfo[@"albumtitle"] forKey:@"albumtitle"];
114 | [song setValue:item.musicInfo[@"artist"] forKey:@"artist"];
115 | [song setValue:item.musicInfo[@"largePictureLocation"] forKey:@"picture"];
116 | [song setValue:item.musicInfo[@"albumLocation"] forKey:@"url"];
117 | [song setValue:@([item.musicInfo[@"rating_avg"] floatValue]) forKey:@"rating_avg"];
118 | [song setValue:date forKey:@"date"];
119 |
120 | [context save:nil];
121 | }
122 |
123 | if ([[NSFileManager defaultManager] fileExistsAtPath:self.recordFileURL.path]) {
124 |
125 | [NSFileVersion addVersionOfItemAtURL: self.recordFileURL
126 | withContentsOfURL: self.recordFileURL
127 | options: 0
128 | error: nil];
129 | }
130 |
131 | [item.musicInfo[@"sid"] writeToURL:self.recordFileURL atomically:YES encoding:NSASCIIStringEncoding error:nil];
132 |
133 | return song;
134 | }
135 |
136 | -(BOOL) addRecordWithDict:(NSDictionary *)dict
137 | {
138 | NSString* sid = dict[@"sid"];
139 | NSString* ssid = dict[@"ssid"];
140 | NSString* aid = dict[@"aid"];
141 | NSString* date = dict[@"date"];
142 | NSString* picture = dict[@"picture"];
143 | NSString* albumtitle = dict[@"albumtitle"];
144 | NSString* rating_avg = dict[@"rating_avg"];
145 | NSString* title = dict[@"title"];
146 | NSString* url = dict[@"url"];
147 | NSString* artist = dict[@"artist"];
148 |
149 | NSManagedObject* theSong = [self songWithSid:sid];
150 | if (theSong) {
151 | return YES;
152 | }
153 | else if (sid && ssid && aid && date && picture && albumtitle && rating_avg
154 | && title && url && artist
155 | )
156 | {
157 | NSManagedObject* song = [NSEntityDescription
158 | insertNewObjectForEntityForName:@"Song"
159 | inManagedObjectContext:context];
160 | [song setValue:sid forKey:@"sid"];
161 | [song setValue:ssid forKey:@"ssid"];
162 | [song setValue:aid forKey:@"aid"];
163 | [song setValue:title forKey:@"title"];
164 | [song setValue:albumtitle forKey:@"albumtitle"];
165 | [song setValue:artist forKey:@"artist"];
166 | [song setValue:picture forKey:@"picture"];
167 | [song setValue:url forKey:@"url"];
168 | [song setValue:rating_avg forKey:@"rating_avg"];
169 | [song setValue:date forKey:@"date"];
170 | return YES;
171 | }
172 | return NO;
173 | }
174 |
175 | -(void) open
176 | {
177 | NSDocumentController* controller =[NSDocumentController sharedDocumentController];
178 | NSArray* documents = [controller documents];
179 | if ([documents count]>0) {
180 | [documents makeObjectsPerformSelector:@selector(close)];
181 | }
182 |
183 | [controller openDocumentWithContentsOfURL:self.recordFileURL
184 | display:YES
185 | error:nil];
186 | }
187 |
188 | -(void) removeCurrentVersion
189 | {
190 | NSFileVersion* current = [NSFileVersion currentVersionOfItemAtURL:self.recordFileURL];
191 | [current removeAndReturnError:nil];
192 | }
193 |
194 | -(void) playSongWith:(NSString *)sid andSsid:(NSString *)ssid
195 | {
196 | [self.delegate playSongWithSid:sid andSsid:ssid];
197 | }
198 |
199 |
200 | -(void) save
201 | {
202 | [context save:nil];
203 | }
204 |
205 | -(NSArray*)allSongs
206 | {
207 | NSFetchRequest* fetchRequset = [NSFetchRequest fetchRequestWithEntityName:@"Song"];
208 | return [context executeFetchRequest:fetchRequset error:nil];
209 | }
210 |
211 | -(void) removeVersionsToLimit{
212 |
213 | if ([[NSFileManager defaultManager] fileExistsAtPath:self.recordFileURL.path]) {
214 | NSInteger limit = [[[NSUserDefaults standardUserDefaults] valueForKey:@"versionsLimit"] integerValue];
215 | NSArray* versions = [NSFileVersion otherVersionsOfItemAtURL:self.recordFileURL];
216 | for (NSInteger i = ([versions count] - 1); i > limit; i--) {
217 | [versions[i] removeAndReturnError:nil];
218 | }
219 | }
220 | [context save:nil];
221 | }
222 |
223 |
224 | @end
225 |
--------------------------------------------------------------------------------
/diumoo/core/DMPlayRecordHandler/DMPlayRecordModel.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | DMPlayRecordModel.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/diumoo/core/DMPlayRecordHandler/DMPlayRecordModel.xcdatamodeld/DMPlayRecordModel.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/diumoo/core/DMPlayableItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DMPlayableItem.swift
3 | // diumoo
4 | //
5 | // Created by Anakin(Yancheng) Zheng on 6/18/16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import AVFoundation
11 | import AppKit
12 |
13 | @objc public enum ItemPlayState : Int {
14 | case waitToPlay, playing, playing_and_will_replay, replaying, replayed
15 | }
16 |
17 | @objc public protocol DMPlayableItemDelegate {
18 | func playableItem(_ item: DMPlayableItem, logStateChanged: Int) -> (Void)
19 | }
20 |
21 | public class DMPlayableItem: AVPlayerItem {
22 | // Interface variables
23 | public var cover : NSImage?
24 | public var isUsingDefaultFailedAlbumPhoto: Bool = false
25 | public var like : Bool
26 | private(set) public var musicInfo : [String: AnyObject]!
27 | public var playState: ItemPlayState
28 | public var delegate: DMPlayableItemDelegate?
29 |
30 | public var floatDuration: Float {
31 | get {
32 | return Float(CMTimeGetSeconds(self.asset.duration))
33 | }
34 | }
35 |
36 | // Const variables
37 | static let douban_URL_prefix = "https://music.douban.com"
38 |
39 | init(WithDict aDict: Dictionary) {
40 | self.musicInfo = [ "subtype":aDict["subtype"]!,
41 | "title":aDict["title"]!,
42 | "artist":aDict["artist"]!,
43 | "albumtitle":aDict["albumtitle"]!,
44 | "musicLocation":aDict["url"]!,
45 | "pictureLocation":aDict["picture"]!]
46 |
47 | let pic = String(describing: aDict["picture"]!)
48 | self.musicInfo["largePictureLocation"] = pic.replacingOccurrences(of:"mpic", with:"lpic") as AnyObject?
49 |
50 | if aDict["aid"] != nil {
51 | self.musicInfo["aid"] = aDict["aid"]!
52 | self.musicInfo["sid"] = aDict["sid"]!
53 | self.musicInfo["ssid"] = aDict["ssid"]!
54 | self.musicInfo["length"] = Float(String(describing: aDict["length"]!))! * 1000 as AnyObject
55 | self.musicInfo["albumLocation"] = String("\(DMPlayableItem.douban_URL_prefix)\(String(describing: aDict["album"]!))") as AnyObject?
56 | }
57 |
58 | self.like = NSString(string: String(describing: aDict["like"]!)).boolValue
59 | self.playState = ItemPlayState.waitToPlay
60 | self.cover = nil
61 |
62 | let dictURL = String(describing: aDict["url"]!)
63 | let aURL = URL(string: dictURL)
64 | let aAsset = AVAsset(url: aURL!)
65 | super.init(asset: aAsset, automaticallyLoadedAssetKeys: nil)
66 |
67 | self.addObserver(self, forKeyPath:"status", options: NSKeyValueObservingOptions(rawValue: UInt(0)), context: nil)
68 | }
69 |
70 | public func invalidItem() {
71 | self.playState = ItemPlayState.waitToPlay
72 | self.removeObserver(self, forKeyPath:"status")
73 | }
74 |
75 | override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
76 | if keyPath == "status" {
77 | print("\(#function) :: \(musicInfo["title"]!) status changed to \(self.status)")
78 | self.delegate?.playableItem(self, logStateChanged: self.status.rawValue)
79 | }
80 | }
81 |
82 | public func shareAttributeWithChannel(_ channel: String) -> String? {
83 | if self.musicInfo["ssid"] != nil {
84 | return String(format:"%@g%@g%@",String(describing: self.musicInfo["sid"]), String(describing: self.musicInfo["ssid"]), channel)
85 | } else {
86 | return nil
87 | }
88 | }
89 |
90 | public func prepareCoverWithCallbackBlock(_ block: @escaping (NSImage?)->Void) {
91 | if self.cover != nil {
92 | block(self.cover!)
93 | return
94 | }
95 |
96 | let strURL = String(describing: musicInfo["largePictureLocation"]!)
97 | let aURL = URL(string: strURL)
98 | let request = URLRequest(url: aURL!, cachePolicy: .useProtocolCachePolicy , timeoutInterval: 5.0)
99 |
100 | let session = URLSession.shared.dataTask(with: request) { data, response, error in
101 | if error != nil || data == nil {
102 | print("\(#function) failed to get album image with reason \(error)")
103 | self.cover = #imageLiteral(resourceName: "albumfail")
104 | self.isUsingDefaultFailedAlbumPhoto = true
105 | } else {
106 | self.cover = NSImage(data: data!)
107 | self.isUsingDefaultFailedAlbumPhoto = false
108 | }
109 | block(self.cover)
110 | }
111 | session.resume()
112 | }
113 |
114 | deinit {
115 | self.delegate = nil
116 | self.invalidItem()
117 | }
118 |
119 | class func playableItem(WithDictionary aDict: Dictionary) -> DMPlayableItem {
120 | return DMPlayableItem.init(WithDict: aDict)
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/diumoo/core/DMService/DMService.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMService.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-8-3.
6 | //
7 | //
8 |
9 | #import
10 | #import "NSData+AESCrypt.h"
11 | #import "NSData+Base64.h"
12 | #import "DMErrorLog.h"
13 |
14 |
15 | #define CURRENT_VERSION 1
16 |
17 |
18 | #define SERVICE_KEY @"-%ZxYx1@99D|ifwN{>*u'<.Rqw]6I:j'"
19 | #define REGISTER_SONG_SERVICE_URL @"http://127.0.0.1:8000/registersong/"
20 |
21 | @interface DMService : NSObject
22 |
23 | +(NSOperationQueue*) serviceQueue;
24 |
25 | +(void)performOnServiceQueue:(void(^)(void))block;
26 | +(void)performOnMainQueue:(void(^)(void))block;
27 | +(NSString*) cleanStartAttribute:(NSString*)start;
28 | +(BOOL) openDiumooLink:(NSString*)url;
29 | +(void) importRecordOperation;
30 | +(void) importRecordOperationWithFilePath:(NSURL*)fp;
31 | +(void) exportRecordOperation;
32 | +(void) showDMNotification;
33 | +(void) shareLinkWithDictionary:(NSDictionary*) dict callback:(void(^)(NSString* url)) block;
34 | +(NSString*) pathToDataFileFolder;
35 | @end
36 |
--------------------------------------------------------------------------------
/diumoo/core/DMShortcutsHandler/DMShortcutsHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMShortcutsHandler.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-7-24.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #define keyPlayShortcut @"playShortcut"
12 | #define keySkipShortcut @"skipShortcut"
13 | #define keyRateShortcut @"rateShortcut"
14 | #define keyBanShortcut @"banShortcut"
15 | #define keyShowPrefsPanel @"showPrefsPanel"
16 | #define keyTogglePanelShortcut @"togglePanelShortcut"
17 |
18 |
19 | @interface DMShortcutsHandler : NSObject
20 |
21 | +(void) registrationShortcuts;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/diumoo/core/DMShortcutsHandler/DMShortcutsHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMShortcutsHandler.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-7-24.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMShortcutsHandler.h"
10 | #import "Shortcut.h"
11 | #import "DMAppDelegate.h"
12 |
13 | @implementation DMShortcutsHandler
14 |
15 | +(void)registrationShortcuts
16 | {
17 |
18 |
19 | [[MASShortcutBinder sharedBinder] bindShortcutWithDefaultsKey:keyPlayShortcut
20 | toAction:^{
21 | [[NSApp delegate]
22 | performSelector:@selector(keyShortcuts:)
23 | withObject:keyPlayShortcut];
24 | }];
25 | [[MASShortcutBinder sharedBinder] bindShortcutWithDefaultsKey:keySkipShortcut
26 | toAction:^{
27 | [[NSApp delegate]
28 | performSelector:@selector(keyShortcuts:)
29 | withObject:keySkipShortcut];
30 | }];
31 |
32 |
33 | [[MASShortcutBinder sharedBinder] bindShortcutWithDefaultsKey:keyRateShortcut
34 | toAction:^{
35 | [[NSApp delegate]
36 | performSelector:@selector(keyShortcuts:)
37 | withObject:keyRateShortcut];
38 | }];
39 |
40 | [[MASShortcutBinder sharedBinder] bindShortcutWithDefaultsKey:keyBanShortcut
41 | toAction:^{
42 | [[NSApp delegate]
43 | performSelector:@selector(keyShortcuts:)
44 | withObject:keyBanShortcut];
45 | }];
46 | [[MASShortcutBinder sharedBinder] bindShortcutWithDefaultsKey:keyTogglePanelShortcut
47 | toAction:^{
48 | [[NSApp delegate]
49 | performSelector:@selector(keyShortcuts:)
50 | withObject:keyTogglePanelShortcut];
51 | }];
52 | [[MASShortcutBinder sharedBinder] bindShortcutWithDefaultsKey:keyShowPrefsPanel
53 | toAction:^{
54 | [[NSApp delegate]
55 | performSelector:@selector(keyShortcuts:)
56 | withObject:keyShowPrefsPanel];
57 | }];
58 |
59 |
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/Dictionary+urlEncoding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+urlEncoding.swift
3 | // diumoo
4 | //
5 | // Created by Yancheng Zheng on 6/18/16.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension Dictionary {
12 |
13 | static func toString(_ object: Any) -> String {
14 | return String(describing: object);
15 | }
16 |
17 | static func urlEncode(_ object: Any) -> String {
18 | let inputString = toString(object);
19 | return inputString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
20 | }
21 |
22 |
23 | func urlEncodedString() -> String {
24 | var parts : Array = []
25 | for (key, value) in self {
26 | let encodedkey = Dictionary.urlEncode(key)
27 | let encodedVal = Dictionary.urlEncode(value)
28 | let part = String("\(encodedkey)=\(encodedVal)")
29 | parts.append(part!)
30 | }
31 | return parts.joined(separator: "&")
32 | }
33 |
34 | func hString() -> String {
35 | var parts : Array = []
36 | for (key, value) in self {
37 | let part = String("\(Dictionary.toString(key)):\(Dictionary.toString(value))")
38 | parts.append(part!)
39 | }
40 | return parts.joined(separator: "|")
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/NSData+AESCrypt.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSData+AESCrypt.h
3 | // DMAESCryptTEST
4 | //
5 | // Created by Shanzi on 12-8-2.
6 | // Copyright (c) 2012年 Shanzi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSData (AESCrypt)
12 |
13 | -(NSData *)AES256EncryptWithKey:(NSString *)key;
14 | -(NSData *)AES256DecryptWithKey:(NSString *)key;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/NSData+AESCrypt.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import "NSData+AESCrypt.h"
3 |
4 | @implementation NSData (AESCrypt)
5 |
6 | - (NSData *)AES256EncryptWithKey:(NSString *)key {
7 | // 'key' should be 32 bytes for AES256, will be null-padded otherwise
8 | char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
9 | bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
10 |
11 | // fetch key data
12 | [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
13 |
14 | NSUInteger dataLength = [self length];
15 |
16 | //See the doc: For block ciphers, the output size will always be less than or
17 | //equal to the input size plus the size of one block.
18 | //That's why we need to add the size of one block here
19 | size_t bufferSize = dataLength + kCCBlockSizeAES128;
20 | void *buffer = malloc(bufferSize);
21 |
22 | size_t numBytesEncrypted = 0;
23 | CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
24 | keyPtr, kCCKeySizeAES256,
25 | "\x00
34 |
35 | @interface NSData (Base64)
36 |
37 | + (NSData *)dataWithBase64EncodedString:(NSString *)string;
38 | - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
39 | - (NSString *)base64EncodedString;
40 |
41 | @end
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/NSData+Base64.m:
--------------------------------------------------------------------------------
1 | //
2 | // Base64.m
3 | //
4 | // Version 1.1
5 | //
6 | // Created by Nick Lockwood on 12/01/2012.
7 | // Copyright (C) 2012 Charcoal Design
8 | //
9 | // Distributed under the permissive zlib License
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/nicklockwood/Base64
13 | //
14 | // This software is provided 'as-is', without any express or implied
15 | // warranty. In no event will the authors be held liable for any damages
16 | // arising from the use of this software.
17 | //
18 | // Permission is granted to anyone to use this software for any purpose,
19 | // including commercial applications, and to alter it and redistribute it
20 | // freely, subject to the following restrictions:
21 | //
22 | // 1. The origin of this software must not be misrepresented; you must not
23 | // claim that you wrote the original software. If you use this software
24 | // in a product, an acknowledgment in the product documentation would be
25 | // appreciated but is not required.
26 | //
27 | // 2. Altered source versions must be plainly marked as such, and must not be
28 | // misrepresented as being the original software.
29 | //
30 | // 3. This notice may not be removed or altered from any source distribution.
31 | //
32 |
33 | #import "NSData+Base64.h"
34 |
35 |
36 | #import
37 | #if !__has_feature(objc_arc)
38 | #error This library requires automatic reference counting
39 | #endif
40 |
41 |
42 | @implementation NSData (Base64)
43 |
44 | + (NSData *)dataWithBase64EncodedString:(NSString *)string
45 | {
46 | const char lookup[] =
47 | {
48 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
49 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
50 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63,
51 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 99, 99, 99,
52 | 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
53 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99,
54 | 99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
55 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99
56 | };
57 |
58 | NSData *inputData = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
59 | long long inputLength = [inputData length];
60 | const unsigned char *inputBytes = [inputData bytes];
61 |
62 | long long maxOutputLength = (inputLength / 4 + 1) * 3;
63 | NSMutableData *outputData = [NSMutableData dataWithLength:maxOutputLength];
64 | unsigned char *outputBytes = (unsigned char *)[outputData mutableBytes];
65 |
66 | int accumulator = 0;
67 | long long outputLength = 0;
68 | unsigned char accumulated[] = {0, 0, 0, 0};
69 | for (long long i = 0; i < inputLength; i++)
70 | {
71 | unsigned char decoded = lookup[inputBytes[i] & 0x7F];
72 | if (decoded != 99)
73 | {
74 | accumulated[accumulator] = decoded;
75 | if (accumulator == 3)
76 | {
77 | outputBytes[outputLength++] = (accumulated[0] << 2) | (accumulated[1] >> 4);
78 | outputBytes[outputLength++] = (accumulated[1] << 4) | (accumulated[2] >> 2);
79 | outputBytes[outputLength++] = (accumulated[2] << 6) | accumulated[3];
80 | }
81 | accumulator = (accumulator + 1) % 4;
82 | }
83 | }
84 |
85 | //handle left-over data
86 | if (accumulator > 0) outputBytes[outputLength] = (accumulated[0] << 2) | (accumulated[1] >> 4);
87 | if (accumulator > 1) outputBytes[++outputLength] = (accumulated[1] << 4) | (accumulated[2] >> 2);
88 | if (accumulator > 2) outputLength++;
89 |
90 | //truncate data to match actual output length
91 | outputData.length = outputLength;
92 | return outputLength? outputData: nil;
93 | }
94 |
95 | - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth
96 | {
97 | //ensure wrapWidth is a multiple of 4
98 | wrapWidth = (wrapWidth / 4) * 4;
99 |
100 | const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
101 |
102 | long long inputLength = [self length];
103 | const unsigned char *inputBytes = [self bytes];
104 |
105 | long long maxOutputLength = (inputLength / 3 + 1) * 4;
106 | maxOutputLength += wrapWidth? (maxOutputLength / wrapWidth) * 2: 0;
107 | unsigned char *outputBytes = (unsigned char *)malloc(maxOutputLength);
108 |
109 | long long i;
110 | long long outputLength = 0;
111 | for (i = 0; i < inputLength - 2; i += 3)
112 | {
113 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2];
114 | outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)];
115 | outputBytes[outputLength++] = lookup[((inputBytes[i + 1] & 0x0F) << 2) | ((inputBytes[i + 2] & 0xC0) >> 6)];
116 | outputBytes[outputLength++] = lookup[inputBytes[i + 2] & 0x3F];
117 |
118 | //add line break
119 | if (wrapWidth && (outputLength + 2) % (wrapWidth + 2) == 0)
120 | {
121 | outputBytes[outputLength++] = '\r';
122 | outputBytes[outputLength++] = '\n';
123 | }
124 | }
125 |
126 | //handle left-over data
127 | if (i == inputLength - 2)
128 | {
129 | // = terminator
130 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2];
131 | outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)];
132 | outputBytes[outputLength++] = lookup[(inputBytes[i + 1] & 0x0F) << 2];
133 | outputBytes[outputLength++] = '=';
134 | }
135 | else if (i == inputLength - 1)
136 | {
137 | // == terminator
138 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2];
139 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0x03) << 4];
140 | outputBytes[outputLength++] = '=';
141 | outputBytes[outputLength++] = '=';
142 | }
143 |
144 | if (outputLength >= 4)
145 | {
146 | //truncate data to match actual output length
147 | outputBytes = realloc(outputBytes, outputLength);
148 | return [[NSString alloc] initWithBytesNoCopy:outputBytes
149 | length:outputLength
150 | encoding:NSASCIIStringEncoding
151 | freeWhenDone:YES];
152 | }
153 | else if (outputBytes)
154 | {
155 | free(outputBytes);
156 | }
157 | return nil;
158 | }
159 |
160 | - (NSString *)base64EncodedString
161 | {
162 | return [self base64EncodedStringWithWrapWidth:0];
163 | }
164 |
165 | @end
166 |
167 |
168 | @implementation NSString (Base64)
169 |
170 | + (NSString *)stringWithBase64EncodedString:(NSString *)string
171 | {
172 | NSData *data = [NSData dataWithBase64EncodedString:string];
173 | if (data)
174 | {
175 | return [[self alloc] initWithData:data encoding:NSUTF8StringEncoding];
176 | }
177 | return nil;
178 | }
179 |
180 | - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth
181 | {
182 | NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
183 | return [data base64EncodedStringWithWrapWidth:wrapWidth];
184 | }
185 |
186 | - (NSString *)base64EncodedString
187 | {
188 | NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
189 | return [data base64EncodedString];
190 | }
191 |
192 | - (NSString *)base64DecodedString
193 | {
194 | return [NSString stringWithBase64EncodedString:self];
195 | }
196 |
197 | - (NSData *)base64DecodedData
198 | {
199 | return [NSData dataWithBase64EncodedString:self];
200 | }
201 |
202 | @end
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/NSDictionary+UrlEncoding.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+UrlEncoding.h
3 | // diumoo-core
4 | //
5 | // 代码来自: http://stackoverflow.com/questions/718429/creating-url-query-parameters-from-nsdictionary-objects-in-objectivec
6 | //
7 | // Created by Shanzi on 12-6-5.
8 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
9 | //
10 |
11 | #import
12 |
13 | @interface NSDictionary (UrlEncoding)
14 | -(NSString*) urlEncodedString;
15 | -(NSString*) hString;
16 | @end
17 |
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/NSDictionary+UrlEncoding.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+UrlEncoding.m
3 | // diumoo-core
4 | //
5 | // Created by Shanzi on 12-6-5.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "NSDictionary+UrlEncoding.h"
10 |
11 | static NSString* toString(id object)
12 | {
13 | return [NSString stringWithFormat:@"%@", object];
14 | }
15 |
16 | static NSString* urlEncode(id object)
17 | {
18 | NSString* inputString = toString(object);
19 | NSString* encodedString = [inputString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
20 | return encodedString;
21 | }
22 |
23 | @implementation NSDictionary (UrlEncoding)
24 |
25 | - (NSString*)urlEncodedString
26 | {
27 | NSMutableArray* parts = [NSMutableArray array];
28 | for (id key in self) {
29 | id value = self[key];
30 | NSString* encodedkey = urlEncode(key);
31 | NSString* encodedValue = urlEncode(value);
32 | NSString* part = [NSString stringWithFormat:@"%@=%@", encodedkey, encodedValue];
33 | [parts addObject:part];
34 | }
35 | return [parts componentsJoinedByString:@"&"];
36 | }
37 |
38 | - (NSString*)hString
39 | {
40 | NSMutableArray* parts = [NSMutableArray array];
41 | for (id key in self) {
42 | id value = self[key];
43 | NSString* part = [NSString stringWithFormat:@"%@:%@", key, value];
44 | [parts addObject:part];
45 | }
46 | return [parts componentsJoinedByString:@"|"];
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/NSImage+AsyncLoadImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+AsyncLoadImage.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-7-30.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface NSImage (AsyncLoadImage)
12 | +(void)AsyncLoadImageWithURLString:(NSString*) urlstring andCallBackBlock:(void(^)(NSImage*))block;
13 | @end
14 |
--------------------------------------------------------------------------------
/diumoo/core/DMUtils/NSImage+AsyncLoadImage.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+AsyncLoadImage.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-7-30.
6 | //
7 | //
8 |
9 | #import "NSImage+AsyncLoadImage.h"
10 | #import "DMErrorLog.h"
11 |
12 | @implementation NSImage (AsyncLoadImage)
13 | +(void)AsyncLoadImageWithURLString:(NSString*) urlstring andCallBackBlock:(void(^)(NSImage*))block
14 | {
15 | dispatch_queue_t imageLoadQueue = dispatch_queue_create("DMImageLoad", NULL);
16 | dispatch_queue_t high = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
17 | dispatch_set_target_queue(imageLoadQueue, high);
18 |
19 | dispatch_async(imageLoadQueue, ^{
20 |
21 | NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlstring]
22 | cachePolicy: NSURLRequestUseProtocolCachePolicy
23 | timeoutInterval:3.0];
24 | NSURLResponse *response;
25 | NSError *error;
26 | NSData *imageData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
27 |
28 | if (error) {
29 | [DMErrorLog logErrorWith:self method:_cmd andError:error];
30 | }
31 |
32 | if (block) {
33 | dispatch_sync(dispatch_get_main_queue(), ^{
34 | block([[NSImage alloc] initWithData:imageData]);
35 | });
36 | }
37 | });
38 | }
39 | @end
40 |
--------------------------------------------------------------------------------
/diumoo/debugLog.h:
--------------------------------------------------------------------------------
1 | //
2 | // debugLog.h
3 | // diumoo
4 | //
5 | // Created by Zheng Anakin on 12-6-9.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #ifdef DEBUG
10 | #define DMLog(format, ...) NSLog(format, ## __VA_ARGS__)
11 | #else
12 | #define DMLog(format, ...)
13 | #endif
--------------------------------------------------------------------------------
/diumoo/diumoo-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // diumoo-Bridging-Header.h
3 | // diumoo
4 | //
5 | // Created by Yancheng Zheng on 6/18/16.
6 | //
7 | //
8 |
9 | #ifndef diumoo_Bridging_Header_h
10 | #define diumoo_Bridging_Header_h
11 |
12 | #import "debugLog.h"
13 | #import "HTMLParser.h"
14 | #import "NSDictionary+UrlEncoding.h"
15 |
16 | #endif /* diumoo_Bridging_Header_h */
17 |
--------------------------------------------------------------------------------
/diumoo/diumoo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | zh_CN
7 | CFBundleDisplayName
8 | diumoo
9 | CFBundleDocumentTypes
10 |
11 |
12 | CFBundleTypeExtensions
13 |
14 | dmplist
15 |
16 | CFBundleTypeIconFile
17 |
18 | CFBundleTypeName
19 | shortcut
20 | CFBundleTypeOSTypes
21 |
22 | ????
23 |
24 | CFBundleTypeRole
25 | Viewer
26 | NSDocumentClass
27 | DMDocument
28 |
29 |
30 | CFBundleTypeExtensions
31 |
32 | dmsid
33 |
34 | CFBundleTypeName
35 | _private_record
36 | CFBundleTypeOSTypes
37 |
38 | ????
39 |
40 | CFBundleTypeRole
41 | Viewer
42 | NSDocumentClass
43 | DMDocument
44 |
45 |
46 | CFBundleTypeExtensions
47 |
48 | dmrecord
49 |
50 | CFBundleTypeIconFile
51 | record.icns
52 | CFBundleTypeName
53 | Play Record
54 | CFBundleTypeOSTypes
55 |
56 | ????
57 |
58 | CFBundleTypeRole
59 | Viewer
60 | NSDocumentClass
61 | DMDocument
62 |
63 |
64 | CFBundleExecutable
65 | ${EXECUTABLE_NAME}
66 | CFBundleIconFile
67 | icon.icns
68 | CFBundleIdentifier
69 | $(PRODUCT_BUNDLE_IDENTIFIER)
70 | CFBundleInfoDictionaryVersion
71 | 6.0
72 | CFBundleName
73 | ${PRODUCT_NAME}
74 | CFBundlePackageType
75 | APPL
76 | CFBundleShortVersionString
77 | 1.6
78 | CFBundleSignature
79 | ????
80 | CFBundleURLTypes
81 |
82 |
83 | CFBundleTypeRole
84 | Viewer
85 | CFBundleURLName
86 | diumoo Share Link
87 | CFBundleURLSchemes
88 |
89 | diumoo
90 |
91 |
92 |
93 | CFBundleVersion
94 | 2626
95 | LSApplicationCategoryType
96 | public.app-category.music
97 | LSMinimumSystemVersion
98 | ${MACOSX_DEPLOYMENT_TARGET}
99 | LSUIElement
100 |
101 | NSAppTransportSecurity
102 |
103 | NSAllowsArbitraryLoads
104 |
105 | NSExceptionDomains
106 |
107 | douban.fm
108 |
109 |
110 |
111 | NSHumanReadableCopyright
112 | Open sourced with GPLv3 license
113 | NSMainNibFile
114 | MainMenu
115 | NSPrincipalClass
116 | NSApplication
117 | NSSupportsAutomaticGraphicsSwitching
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/diumoo/diumoo-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'diumoo' target in the 'diumoo' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #import
7 | #import "debugLog.h"
8 | #endif
9 |
--------------------------------------------------------------------------------
/diumoo/en.lproj/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg936\cocoartf1138\cocoasubrtf470
2 | {\fonttbl\f0\fnil\fcharset134 STHeitiSC-Light;\f1\fswiss\fcharset0 Helvetica;\f2\fswiss\fcharset0 ArialMT;
3 | }
4 | {\colortbl;\red255\green255\blue255;\red63\green0\blue63;}
5 | \paperw11900\paperh16840\vieww9600\viewh8400\viewkind0
6 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
7 |
8 | \f0\b\fs24 \cf0 Developed By
9 | \f1 :
10 | \b0 \
11 | Shanzi, Anakin Zheng, Sean Lee\
12 | \
13 |
14 | \f0\b UI
15 | \f1 :
16 | \b0 \
17 |
18 | \f2\fs28 \cf2 chumsdock
19 | \f0 ,
20 | \f1\fs24 \cf0 Shanzi\
21 | \
22 | \
23 | \
24 | }
--------------------------------------------------------------------------------
/diumoo/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/diumoo/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /* No comment provided by engineer. */
2 | "PLAY_ALBUM_FAILED" = "Play Album Failed";
3 |
4 | /* No comment provided by engineer. */
5 | "PLAY_ALBUM_FAILED_DETAIL" = "The album you request to play is invalid.";
6 |
7 | /* No comment provided by engineer. */
8 | "PRIVATE_MHZ" = "Private MHz";
9 |
10 | /* No comment provided by engineer. */
11 | "SOUNDTRACK_MHZ" = "Soundtrack";
12 |
13 | /* No comment provided by engineer. */
14 | "EXPORT" = "Export";
15 |
16 | /* No comment provided by engineer. */
17 | "EXPORT_PLAY_RECORD" = "Export Play Record";
18 |
19 | /* No comment provided by engineer. */
20 | "IMPORT" = "Import";
21 |
22 | /* 导入失败 */
23 | "IMPORT_FAILED" = "Import Failed";
24 |
25 | /* 导入播放记录失败,您试图导入的文件类型不正确或者文件已损坏。 */
26 | "IMPORT_FAILED_DETAIL" = "The play record file is broken or invalid.";
27 |
28 | /* 导入播放记录 */
29 | "IMPORT_PLAY_RECORD" = "Import Play Record";
30 |
31 | /* No comment provided by engineer. */
32 | "OPEN_URL_FAILED" = "Open URL Failed";
33 |
34 | /* 未能成功打开您指定的URL,可能是您试图播放的专辑、音乐家或电影原声不可用。 */
35 | "OPEN_URL_FAILED_DETAIL" = "Failed to open URL. It seems that the album, songs of artist or soundtrack you request to play is invalid.";
36 |
37 | /* 查看详细 */
38 | "SHOW_DETAIL" = "Show Details";
39 |
40 | /* No comment provided by engineer. */
41 | "SUCCESS_EXPORT" = "Export Success";
42 |
43 | /* 成功导出 %ld 首歌曲的播放记录。 */
44 | "SUCCESS_EXPORT_DETAIL" = "Success to export play record of %ld songs.";
45 |
46 | /* No comment provided by engineer. */
47 | "SUCCESS_IMPORT" = "Import Success";
48 |
49 | /* 成功导入了 %ld 个歌曲记录,失败 %ld 个。 */
50 | "SUCCESS_IMPORT_DETAIL" = "Success to import play record of %ld songs with %ld failed.";
51 |
52 | /* No comment provided by engineer. */
53 | "IMPORT_PLAY_RECORD" = "Import Play Record";
54 |
55 | /* No comment provided by engineer. */
56 | "IMPORT_PLAY_RECORD_DETAIL" = "You have just opened a diumoo play record file, import it now?";
57 | /* No comment provided by engineer. */
58 | "NO" = "No";
59 |
60 | /* No comment provided by engineer. */
61 | "OPEN_FILE_FAILED" = "Failed to open File";
62 |
63 | /* No comment provided by engineer. */
64 | "YES" = "Yes";
65 |
66 | /* public */
67 | "LOCALIZED_PUBLIC_LIST_NAME" = "en_public";
68 |
69 | /* 发生网络错误,请尝试重启应用 */
70 | "NETWORK_ERROR_INDICADTE_STRING"="Request Timeout";
71 |
72 | /* 专辑:《%@》 */
73 | "ALBUM_DOCUMENT_TITLE" = "Album : %@";
74 |
75 | /* 专辑名 */
76 | "DETAIL_ALBUM" = "Album Title";
77 |
78 | /* 唱片数 */
79 | "DETAIL_DISCS" = "Discs";
80 |
81 | /* 豆瓣评分 */
82 | "DETAIL_DOUBAN_RATING" = "Rating";
83 |
84 | /* 条形码 */
85 | "DETAIL_EAN" = "Ean";
86 |
87 | /* 介质 */
88 | "DETAIL_MEDIA" = "Media";
89 |
90 | /* 发行时间 */
91 | "DETAIL_PUBDATE" = "Pub-date";
92 |
93 | /* 出版者 */
94 | "DETAIL_PUBLISHER" = "Publisher";
95 |
96 | /* %@ (%@ 人评价) */
97 | "DETAIL_RATES" = "%@ (%@ ratings)";
98 |
99 | /* 歌手 */
100 | "DETAIL_SINGER" = "Artist";
101 |
102 | /* 版本特性 */
103 | "DETAIL_VERSION" = "Version";
104 |
105 | /* 获取详细信息失败 */
106 | "GET_DETAIL_FAILED" = "Get album detail failed.";
107 |
108 | /* 解析信息失败 */
109 | "PARSE_DETAIL_FAILED" = "Parse album detail failed.";
110 |
111 | /* 解析信息成功! */
112 | "PARSE_DETAIL_SUCCESS" = "Get detail success.";
113 |
114 | /* 简介 */
115 | "DETAIL_ABSTRACT" = "Abstract";
116 |
117 | /* 专辑信息 */
118 | "DETAIL_ALBUM_INFO" = "Album Info";
119 |
120 | /* 曲目 */
121 | "DETAIL_SONGS" = "songs";
122 |
123 | /* 未知 */
124 | "DETAIL_UNKNOWN" = "unknown";
125 |
126 | /* 需要验证码 */
127 | "INVALID_CAPTCHA_CODE" = "Haven't fetch captcha yet";
128 |
129 | /* 验证码不能为空 */
130 | "CAPTCHA_MUST_NOT_BE_EMPTY" = "Captcha must not be empty";
131 |
132 | /* 邮箱不能为空 */
133 | "EMAIL_MUST_NOT_BE_EMPTY" = "Email must not be empty";
134 |
135 | /* 获取失败,请重试 */
136 | "FETCH_CAPTCHA_FAILED" = "Failed to fetch Captcha image";
137 |
138 | /* 登陆失败! */
139 | "LOGIN_FAILED" = "Failed to login";
140 |
141 | /* 密码不能为空 */
142 | "PASSWORD_MUST_NOT_BE_EMPTY" = "Password must not be empty";
143 |
144 | /* 关于 */
145 | "PREF_ABOUT" = "About";
146 |
147 | /* 账户 */
148 | "PREF_ACCOUNT" = "Account";
149 |
150 | /* 通用 */
151 | "PREF_GENERAL" = "General";
152 |
153 | /* 快捷键 */
154 | "PREF_SHORTCUTS" = "Shortcuts";
155 |
156 | /* 详细信息 */
157 | "DETAIL" = "Detail";
158 |
159 | /* 预览 */
160 | "PREVIEW" = "Preview";
161 |
162 | /* 豆瓣FM PRO */
163 | "PRO_NEED_BUY_TITLE" = "Douban FM Pro";
164 |
165 | /* 豆瓣FM PRO 说明 */
166 | "PRO_NEED_BUY" = "You can only play music of higher bitrate after paid for douban FM Pro. This service is provided by douban and has no relationship with diumoo.\n\nDo you want to know more?" ;
167 |
168 | /* 音乐比特率改变 */
169 | "BITRATE_CHANGED" = "Bitrate of Music Changed";
170 |
171 | /* 音乐比特率改变到 */
172 | "BITRATE_CHANGED_TO_VALUE" = "Current bitrate of music is ";
173 |
174 | /* 分享链接已复制 */
175 | "SHARE_LINK_TITLE" = "share link copied";
176 |
177 |
--------------------------------------------------------------------------------
/diumoo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-7.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "DMApp.h"
11 |
12 | int main(int argc, char *argv[])
13 | {
14 | @autoreleasepool {
15 | [DMApp sharedApplication];
16 | [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:nil];
17 | [NSApp run];
18 | }
19 | return 0;
20 | }
21 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMBitrateControlLayer/DMBitrateControlLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMBitrateControlLayer.h
3 | // DMBitrateSelectLayer
4 | //
5 | // Created by Shanzi on 13-1-18.
6 | // Copyright (c) 2013年 Shanzi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DMBitrateControlLayer : CALayer
12 | {
13 | NSArray* LayerArray;
14 | CGColorRef black;
15 | CGColorRef focus;
16 | }
17 |
18 | -(BOOL) hitPostion:(NSPoint) point;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMBitrateControlLayer/DMBitrateControlLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMBitrateControlLayer.m
3 | // DMBitrateSelectLayer
4 | //
5 | // Created by Shanzi on 13-1-18.
6 | // Copyright (c) 2013年 Shanzi. All rights reserved.
7 | //
8 |
9 | #import "DMBitrateControlLayer.h"
10 |
11 | @implementation DMBitrateControlLayer
12 | -(id)init
13 | {
14 | self = [super init];
15 | if (self) {
16 | self.frame = CGRectMake(0, 0, 250, 40);
17 | self.anchorPoint = CGPointMake(0, 0);
18 |
19 | LayerArray = @[[CALayer new],[CALayer new],[CALayer new]];
20 |
21 | int count=0;
22 | NSArray* imagenames=@[@"64kbps",@"128kbps",@"192kbps"];
23 | black = CGColorCreateGenericGray(0, 0.6);
24 | focus = CGColorCreateGenericRGB(0.2, 0.5, 1.0, 1.0);
25 | CGRect frame = CGRectMake(0, 0, 70, 40);
26 |
27 | for (CALayer* layer in LayerArray) {
28 | layer.frame = frame;
29 | layer.anchorPoint = CGPointMake(0, 0);
30 | layer.backgroundColor = black;
31 | layer.position = CGPointMake(72*count +17 , 10);
32 | layer.contents = [NSImage imageNamed:imagenames[count]];
33 | [self addSublayer:layer];
34 | count ++;
35 | }
36 |
37 | [[NSUserDefaults standardUserDefaults] addObserver:self
38 | forKeyPath:@"musicQuality"
39 | options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
40 | context:nil];
41 |
42 | }
43 | return self;
44 | }
45 |
46 | -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
47 | {
48 |
49 | NSInteger bitrate = [[NSUserDefaults standardUserDefaults] integerForKey:@"musicQuality"];
50 | [self selectLayer:LayerArray[bitrate/64-1]];
51 | }
52 |
53 | -(void) selectLayer:(CALayer*) layer
54 | {
55 | [CATransaction begin];
56 | for (CALayer* l in LayerArray) {
57 | if (l==layer) {
58 | l.backgroundColor = focus;
59 | l.position = CGPointMake(l.position.x, 10);
60 | }
61 | else{
62 | l.backgroundColor=black;
63 | l.position = CGPointMake(l.position.x, 0);
64 | }
65 | }
66 | [CATransaction commit];
67 | }
68 |
69 | -(BOOL) hitPostion:(NSPoint)point
70 | {
71 | if (point.y>40)
72 | return NO;
73 | int bitrate = 0;
74 | if (point.x>17)
75 | {
76 | if (point.x<17+72)
77 | bitrate = 64;
78 | else if(point.x < 17+72*2)
79 | bitrate = 128;
80 | else if(point.x < 17+72*3)
81 | bitrate = 192;
82 | }
83 | if(bitrate) {
84 | NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
85 | if ([defaults boolForKey:@"isPro"]) {
86 | if ([defaults integerForKey:@"musicQuality"]!=bitrate) {
87 | [defaults setInteger:bitrate
88 | forKey:@"musicQuality"];
89 | }
90 | }
91 | else{
92 | NSInteger re = NSRunInformationalAlertPanel(NSLocalizedString(@"PRO_NEED_BUY_TITLE", nil),
93 | NSLocalizedString(@"PRO_NEED_BUY", nil),
94 | NSLocalizedString(@"YES", nil),
95 | NSLocalizedString(@"NO", nil),
96 | nil);
97 | if (re==NSAlertDefaultReturn) {
98 | [[NSWorkspace sharedWorkspace] openURL:
99 | [NSURL URLWithString:@"https://douban.fm/upgrade"]];
100 | }
101 | }
102 |
103 | return YES;
104 | }
105 | return NO;
106 | }
107 |
108 | @end
109 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMButton/DMButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMControlButtonCell.h
3 | // diumoo
4 | //
5 | // Created by AnakinGWY on 12-8-15.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface DMButton : NSButton {
12 | NSTrackingArea* trackingArea;
13 | }
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMButton/DMButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMControlButtonCell.m
3 | // diumoo
4 | //
5 | // Created by AnakinGWY on 12-8-15.
6 | //
7 | //
8 |
9 | #import "DMButton.h"
10 |
11 | @implementation DMButton
12 |
13 | - (id)init
14 | {
15 | if (self = [super init]) {
16 | }
17 | return self;
18 | }
19 |
20 | - (void)awakeFromNib
21 | {
22 | [[self window] setAcceptsMouseMovedEvents:YES];
23 | [super awakeFromNib];
24 | }
25 |
26 | - (void)mouseEntered:(NSEvent*)theEvent
27 | {
28 | if ([self isEnabled]) {
29 | NSString* name = [[self image] name];
30 | NSImage* mouseoverImage = [NSImage imageNamed:[name stringByAppendingString:@"_mouseover"]];
31 | if (mouseoverImage != nil) {
32 | [self setImage:mouseoverImage];
33 | }
34 | }
35 | }
36 | - (void)mouseExited:(NSEvent*)theEvent
37 | {
38 | if ([self isEnabled]) {
39 | NSString* name = [[self image] name];
40 | NSImage* normalImage = [NSImage imageNamed:[name stringByReplacingOccurrencesOfString:@"_mouseover" withString:@""]];
41 | if (normalImage != nil) {
42 | [self setImage:normalImage];
43 | }
44 | }
45 | }
46 |
47 | - (void)updateTrackingAreas
48 | {
49 | [self removeTrackingArea:trackingArea];
50 |
51 | NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow;
52 | trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil];
53 |
54 | [self addTrackingArea:trackingArea];
55 |
56 | [super updateTrackingAreas];
57 | }
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMCoverControlView/DMCoverControlView.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMCoverControlView.h
3 | // diumoo-main-ui
4 | //
5 | // Created by Shanzi on 12-5-31.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "DMCoverSlide.h"
11 | #import "DMBitrateControlLayer.h"
12 |
13 | @interface DMCoverControlView : NSButton
14 | {
15 | CALayer* mainLayer;
16 | DMCoverSlide* slide;
17 | DMBitrateControlLayer* bitratelayer;
18 | }
19 | @property(readonly)DMCoverSlide* slide;
20 |
21 | -(void) setPlayingInfo:(NSString*) musictitle
22 | :(NSString*) artist
23 | :(NSString*) albumTitle ;
24 |
25 | -(void) setAlbumImage:(NSImage*) albumImage;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMCoverControlView/DMCoverControlView.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMCoverControlView.m
3 | // diumoo-main-ui
4 | //
5 | // Created by Shanzi on 12-5-31.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMCoverControlView.h"
10 |
11 | @implementation DMCoverControlView
12 | @synthesize slide;
13 |
14 | - (id)initWithFrame:(NSRect)frame
15 | {
16 | self = [super initWithFrame:frame];
17 | if (self) {
18 | mainLayer = [[CALayer alloc] init];
19 |
20 | mainLayer.frame = frame;
21 | mainLayer.masksToBounds = YES;
22 |
23 | slide = [[DMCoverSlide alloc] init];
24 | slide.anchorPoint = CGPointMake(0, 0);
25 | slide.position =slide.anchorPoint;
26 |
27 | [mainLayer addSublayer:slide];
28 |
29 | bitratelayer = [[DMBitrateControlLayer alloc] init];
30 |
31 | bitratelayer.position = CGPointMake(0, frame.size.height);
32 |
33 | [mainLayer addSublayer:bitratelayer];
34 |
35 | [self setWantsLayer:YES];
36 | [self setLayer:mainLayer];
37 |
38 | [self addTrackingRect:self.bounds
39 | owner:self
40 | userData:NULL assumeInside:NO];
41 |
42 | }
43 |
44 | return self;
45 | }
46 |
47 | -(BOOL) acceptsFirstResponder
48 | {
49 | return YES;
50 | }
51 |
52 | -(void) mouseEntered:(NSEvent *)event
53 | {
54 | [slide setOpacity:0.6];
55 | bitratelayer.position = CGPointMake(0, -20);
56 | }
57 |
58 | -(void) mouseExited:(NSEvent *)event
59 | {
60 | [slide setOpacity:1.0];
61 | bitratelayer.position = CGPointMake(0, -50);
62 | }
63 |
64 | -(void) mouseDown:(NSEvent *)theEvent
65 | {
66 | NSPoint location = [self convertPoint:[theEvent locationInWindow] fromView:self.window.contentView];
67 |
68 | if (![bitratelayer hitPostion:location]) {
69 | [NSApp sendAction:self.action to:self.target from:self];
70 | }
71 |
72 | }
73 |
74 |
75 | -(void) setPlayingInfo:(NSString *)musictitle :(NSString *)artist :(NSString *)albumTitle
76 | {
77 | [self.slide setTitle:musictitle artist:artist andAlbum:albumTitle];
78 |
79 | }
80 |
81 | -(void) setAlbumImage:(NSImage *)albumImage
82 | {
83 | [self.slide setFrontCoverImage:albumImage];
84 | }
85 |
86 |
87 | @end
88 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMCoverSlide/DMCoverSlide.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMCoverSlide.h
3 | // diumoo-main-ui
4 | //
5 | // Created by Shanzi on 12-5-30.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #define BOUNDS CGRectMake(0,0,250,330)
10 | #define FRONT_BOUNDS CGRectMake(0,0,250,250)
11 | #define TITLE_BOUNDS CGRectMake(0,0,230,30)
12 | #define ARTIST_BOUNDS CGRectMake(0,0,230,20)
13 | #define ALBUM_BOUNDS CGRectMake(0,0,230,20)
14 |
15 | #import
16 |
17 | @interface DMCoverSlide : CALayer
18 | {
19 | CGPoint frontPosition;
20 | CGPoint titlePosition;
21 | CGPoint artistPosition;
22 | CGPoint albumPosition;
23 |
24 | CALayer* frontCover;
25 | CALayer* frontFadeTransitionLayer;
26 |
27 | CATextLayer* titleLayer;
28 | CATextLayer* artistLayer;
29 | CATextLayer* albumLayer;
30 | }
31 | @property(readonly) CALayer* frontCover;
32 |
33 |
34 | -(void) setTitle:(NSString*) title artist:(NSString*)artist andAlbum:(NSString*) album;
35 |
36 | -(void) setFrontCoverImage:(NSImage*) image;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMCoverSlide/DMCoverSlide.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMCoverSlide.m
3 | // diumoo-main-ui
4 | //
5 | // Created by Shanzi on 12-5-30.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMCoverSlide.h"
10 |
11 | @implementation DMCoverSlide
12 | @synthesize frontCover;
13 |
14 | -(id) init
15 | {
16 | if (self = [super init]) {
17 | frontPosition = CGPointMake(0,0);
18 | titlePosition = CGPointMake(10,260);
19 | artistPosition = CGPointMake(13,283);
20 | albumPosition = CGPointMake(13,301);
21 | self.bounds = BOUNDS;
22 | self.masksToBounds = YES;
23 |
24 | CGFloat currentScale = [NSScreen mainScreen].backingScaleFactor;
25 |
26 | // init
27 | frontCover = [[CALayer alloc] init];
28 | frontFadeTransitionLayer = [[CALayer alloc] init];
29 |
30 | titleLayer = [[CATextLayer alloc] init];
31 | artistLayer = [[CATextLayer alloc] init];
32 | albumLayer = [[CATextLayer alloc] init];
33 |
34 | frontCover.delegate = self;
35 | frontFadeTransitionLayer.delegate = self;
36 |
37 | titleLayer.delegate = self;
38 | artistLayer.delegate = self;
39 | albumLayer.delegate = self;
40 |
41 | frontCover.contentsScale = currentScale;
42 | frontFadeTransitionLayer.contentsScale = currentScale;
43 | titleLayer.contentsScale = currentScale;
44 | artistLayer.contentsScale = currentScale;
45 | albumLayer.contentsScale = currentScale;
46 |
47 | // anchor
48 | CGPoint anchor = CGPointMake(0, 0);
49 |
50 | frontCover.anchorPoint = anchor;
51 | frontFadeTransitionLayer.anchorPoint = anchor;
52 |
53 | titleLayer.anchorPoint = anchor;
54 | artistLayer.anchorPoint = anchor;
55 | albumLayer.anchorPoint = anchor;
56 |
57 | // position
58 | frontCover.position = frontPosition;
59 | frontFadeTransitionLayer.position = anchor;
60 |
61 | titleLayer.position = titlePosition;
62 | artistLayer.position = artistPosition;
63 | albumLayer.position = albumPosition;
64 |
65 | // bounds
66 | frontCover.bounds = FRONT_BOUNDS;
67 | frontFadeTransitionLayer.bounds = FRONT_BOUNDS;
68 | titleLayer.bounds = TITLE_BOUNDS;
69 | artistLayer.bounds = ARTIST_BOUNDS;
70 | albumLayer.bounds = ALBUM_BOUNDS;
71 |
72 |
73 | // gravity
74 | frontCover.contentsGravity = kCAGravityResizeAspectFill;
75 | frontFadeTransitionLayer.contentsGravity = kCAGravityResizeAspectFill;
76 |
77 | // text
78 | CGFontRef helveticaConsensedBold = CGFontCreateWithFontName((CFStringRef)@"Helvetica Neue Condensed Bold");
79 | CGFontRef helveticaLight = CGFontCreateWithFontName((CFStringRef)@"Helvetica Neue Light");
80 | CGColorRef titleColor = CGColorCreateGenericRGB(0.2, 0.5, 1.0, 1.0);
81 | CGColorRef lighterColor = CGColorCreateGenericGray(0.2, 1.0);
82 |
83 | titleLayer.font = helveticaConsensedBold;
84 | artistLayer.font = helveticaLight;
85 | albumLayer.font = helveticaLight;
86 |
87 | titleLayer.fontSize = 18;
88 | artistLayer.fontSize = 13;
89 | albumLayer.fontSize = 13;
90 |
91 | titleLayer.foregroundColor = titleColor;
92 | artistLayer.foregroundColor = lighterColor;
93 | albumLayer.foregroundColor = lighterColor;
94 |
95 | titleLayer.truncationMode = kCATruncationEnd;
96 | artistLayer.truncationMode = kCATruncationEnd;
97 | albumLayer.truncationMode = kCATruncationEnd;
98 |
99 | CGFontRelease(helveticaConsensedBold);
100 | CGFontRelease(helveticaLight);
101 | CGColorRelease(titleColor);
102 | CGColorRelease(lighterColor);
103 |
104 | // opacity
105 | frontFadeTransitionLayer.opacity = 0;
106 |
107 | // sublayer
108 | [frontCover setMasksToBounds:YES];
109 | [frontCover addSublayer:frontFadeTransitionLayer];
110 | [self addSublayer:frontCover];
111 | [self addSublayer:titleLayer];
112 | [self addSublayer:artistLayer];
113 | [self addSublayer:albumLayer];
114 | }
115 | return self;
116 | }
117 |
118 |
119 | -(void)setTitle:(NSString *)title artist:(NSString *)artist andAlbum :(NSString *)album
120 | {
121 | [CATransaction begin];
122 | [CATransaction setCompletionBlock:^{
123 | titleLayer.string = title;
124 | artistLayer.string = artist;
125 | albumLayer.string = album;
126 |
127 | titleLayer.opacity = 1;
128 | artistLayer.opacity = 1;
129 | albumLayer.opacity = 1;
130 |
131 | }];
132 | titleLayer.opacity = 0;
133 | artistLayer.opacity = 0;
134 | albumLayer.opacity = 0;
135 | [CATransaction commit];
136 |
137 | }
138 |
139 | -(void) setFrontCoverImage:(NSImage *)image
140 | {
141 | [CATransaction begin];
142 | frontFadeTransitionLayer.contents = image;
143 | [CATransaction setAnimationDuration:1.0];
144 | [CATransaction setAnimationTimingFunction:
145 | [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
146 | [CATransaction setCompletionBlock:^{
147 | [CATransaction begin];
148 | [CATransaction setAnimationDuration:0.0];
149 | frontCover.contents = image;
150 | frontFadeTransitionLayer.opacity = 0.0;
151 | [CATransaction commit];
152 | }];
153 | frontFadeTransitionLayer.opacity = 1.0;
154 | [CATransaction commit];
155 | }
156 |
157 | - (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale
158 | fromWindow:(NSWindow *)window
159 | {
160 | return YES;
161 | }
162 |
163 | @end
164 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMPanel.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMPanel.h
3 | // diumoo
4 | //
5 | // Created by Anakin Zheng on 12-8-14.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface DMPanel : NSPanel
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMPanel.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMPanel.m
3 | // diumoo
4 | //
5 | // Created by Anakin Zheng on 12-8-14.
6 | //
7 | //
8 |
9 | #import "DMPanel.h"
10 | #import "DMPanelWindowController.h"
11 |
12 | @implementation DMPanel
13 |
14 | - (BOOL)canBecomeKeyWindow;
15 | {
16 | return YES; // Allow Search field to become the first responder
17 | }
18 |
19 | - (void)scrollWheel:(NSEvent*)theEvent
20 | {
21 | [self.delegate performSelector:@selector(mouseScroll:)
22 | withObject:theEvent];
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMPanelWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMPannelWindowController.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-12.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMButton.h"
10 | #import "DMCoverControlView.h"
11 | #import "diumoo-Swift.h"
12 | #import "DMPopUpMenuController.h"
13 | #import "MenubarController.h"
14 | #import
15 |
16 | typedef enum {
17 | DOUBAN = 1,
18 | FANFOU = 2,
19 | SINA_WEIBO = 3,
20 | TWITTER = 4,
21 | FACEBOOK = 5,
22 | SYS_TWITTER = 6,
23 | SYS_FACEBOOK = 7,
24 | SYS_WEIBO = 8,
25 | COPY_LINK = 9
26 |
27 | } SNS_CODE;
28 |
29 | @protocol DMPanelWindowDelegate
30 |
31 | - (void)playOrPause;
32 | - (void)skip;
33 | - (void)rateOrUnrate;
34 | - (void)ban;
35 | - (void)volumeChange:(float)volume;
36 | - (BOOL)channelChangedTo:(NSString*)channel;
37 | - (void)exitedSpecialMode;
38 | - (void)share:(SNS_CODE)code;
39 |
40 | @end
41 |
42 | @interface DMPanelWindowController : NSWindowController {
43 | IBOutlet DMCoverControlView* coverView;
44 | IBOutlet DMPopUpMenuController* popupMenuController;
45 |
46 | IBOutlet DMButton* playPauseButton;
47 | IBOutlet DMButton* skipButton;
48 | IBOutlet DMButton* rateButton;
49 | IBOutlet DMButton* banButton;
50 |
51 | IBOutlet NSButton* userIconButton;
52 | IBOutlet NSTextField* usernameTextField;
53 |
54 | IBOutlet NSProgressIndicator* loadingIndicator;
55 | IBOutlet NSTextField* indicateString;
56 |
57 | BOOL _hasActivePanel;
58 | MenubarController* menubarController;
59 | }
60 |
61 | @property (nonatomic, strong) IBOutlet DMCoverControlView* coreView;
62 |
63 | @property (copy) NSString* openURL;
64 | @property (nonatomic) BOOL hasActivePanel;
65 |
66 | @property (strong) IBOutlet id delegate;
67 |
68 | + (DMPanelWindowController*)sharedWindowController;
69 |
70 | - (void)channelChangeActionWithSender:(id)sender;
71 | - (IBAction)controlAction:(id)sender;
72 | - (IBAction)showAlbumWindow:(id)sender;
73 | - (IBAction)specialAction:(id)sender;
74 | - (IBAction)shareAction:(id)sender;
75 |
76 | - (void)unlockUIWithError:(BOOL)has_err;
77 | - (void)setRated:(BOOL)rated;
78 | - (void)setPlaying:(BOOL)playing;
79 | - (void)setPlayingItem:(DMPlayableItem*)item;
80 | - (void)playDefaultChannel;
81 |
82 | - (NSString*)switchToDefaultChannel;
83 | - (void)invokeChannelWithCid:(NSInteger)cid andTitle:(NSString*)title andPlay:(BOOL)immediately;
84 |
85 | - (void)toggleSpecialWithDictionary:(NSDictionary*)info;
86 | - (IBAction)togglePanel:(id)sender;
87 | - (void)mouseScroll:(NSEvent*)event;
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMPopUpButtonCell/DMPopUpButtonCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMPopUpButtonCell.h
3 | // DMSubclassNSCellTest
4 | //
5 | // Created by Shanzi on 12-6-14.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DMPopUpButtonCell : NSButtonCell
12 | {
13 | NSDictionary* stringAttribute;
14 | NSDictionary* stringHighligtAttribute;
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMPopUpButtonCell/DMPopUpButtonCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMPopUpButtonCell.m
3 | // DMSubclassNSCellTest
4 | //
5 | // Created by Shanzi on 12-6-14.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMPopUpButtonCell.h"
10 |
11 | #define HIGH_LIGHT_ATTRIBUTE [NSDictionary dictionaryWithObject:[NSColor whiteColor] forKey:NSForegroundColorAttributeName]
12 |
13 | @implementation DMPopUpButtonCell
14 |
15 |
16 | -(void) drawTitleWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
17 | {
18 | NSString* label = self.title;
19 | NSAttributedString* string = [[NSAttributedString alloc] initWithString:label
20 | attributes:[self stringAttribute]];
21 | NSSize stringSize = string.size;
22 | NSRect stringRect = NSMakeRect(cellFrame.origin.x + 10,
23 | NSMidY(cellFrame) - stringSize.height/2,
24 | cellFrame.size.width - 40, stringSize.height);
25 | [string drawInRect:stringRect];
26 |
27 | }
28 |
29 | -(NSDictionary*) stringAttribute
30 | {
31 | if ([self isHighlighted]) {
32 | if (stringHighligtAttribute) {
33 | return stringHighligtAttribute;
34 | }
35 | else {
36 | NSMutableParagraphStyle* ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
37 | [ps setLineBreakMode:NSLineBreakByTruncatingTail];
38 |
39 | stringHighligtAttribute = @{NSForegroundColorAttributeName: [NSColor selectedMenuItemTextColor],
40 | NSParagraphStyleAttributeName: ps,
41 | NSFontAttributeName: self.font};
42 | return stringHighligtAttribute;
43 | }
44 | }
45 | else {
46 | if (stringAttribute) {
47 | return stringAttribute;
48 | }
49 | else {
50 | NSMutableParagraphStyle* ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
51 | [ps setLineBreakMode:NSLineBreakByTruncatingTail];
52 |
53 | stringAttribute = @{NSForegroundColorAttributeName: [NSColor blackColor],
54 | NSParagraphStyleAttributeName: ps,
55 | NSFontAttributeName: self.font};
56 | return stringAttribute;
57 | }
58 | }
59 | }
60 |
61 | -(void) drawBorderAndBackgroundWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
62 | {
63 | NSBezierPath* rect = [NSBezierPath bezierPathWithRect:cellFrame];
64 | [rect setLineWidth:1.0];
65 | [[NSColor colorWithGenericGamma22White:0.6 alpha:1.0] setStroke];
66 |
67 | NSBezierPath* tri = [[NSBezierPath alloc] init];
68 | [tri moveToPoint:NSMakePoint(cellFrame.size.width - 20, NSMidY(cellFrame) - 5)];
69 | [tri lineToPoint:NSMakePoint(cellFrame.size.width - 20, NSMidY(cellFrame) + 5)];
70 | [tri lineToPoint:NSMakePoint(cellFrame.size.width + 5*sqrt(3) - 20, NSMidY(cellFrame))];
71 | [tri closePath];
72 |
73 | if([self isHighlighted])
74 | {
75 | [[NSColor selectedMenuItemColor] setFill];
76 | [rect fill];
77 | [rect stroke];
78 |
79 | [[NSColor whiteColor]setFill];
80 | [tri fill];
81 | }
82 |
83 | else
84 | {
85 | [[NSColor whiteColor] setFill];
86 | [rect fill];
87 | [rect stroke];
88 | [tri stroke];
89 | }
90 | }
91 |
92 | -(void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
93 | {
94 | [self drawBorderAndBackgroundWithFrame:cellFrame inView:controlView];
95 | [self drawTitleWithFrame:cellFrame inView:controlView];
96 | }
97 |
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMPopUpButtonCell/DMPopUpMenuController.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMPopUpMenuController.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-16.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface DMPopUpMenuController : NSObjectController
13 | {
14 | IBOutlet NSButton* mainButton;
15 | IBOutlet NSButton* longMainButton;
16 | IBOutlet NSButton* subButton;
17 |
18 | IBOutlet NSMenu * mainMenu;
19 | IBOutlet NSMenu * moreChannelMenu;
20 | IBOutlet NSMenu* exitSpecialMenu;
21 |
22 | IBOutlet NSMenu* shareMenu;
23 |
24 | }
25 |
26 | @property(strong) IBOutlet id delegate;
27 |
28 | @property(strong) NSMenu* publicMenu;
29 | @property(strong) NSMenu* suggestMenu;
30 |
31 | @property NSInteger currentChannelID;
32 | @property(strong) id currentChannelMenuItem;
33 |
34 | @property BOOL specialMode;
35 |
36 | -(IBAction)popUpMenu:(id)sender;
37 | -(IBAction)changeChannelAction:(id)sender;
38 | -(void) updateChannelMenuWithSender:(id)sender;
39 | -(void) updateChannelList;
40 |
41 | -(void) enterSpecialPlayingModeWithTitle:(NSString *)title artist:(NSString*)artist andTypeString:(NSString*) type;
42 | -(void) exitSepecialPlayingMode;
43 | -(void) setPrivateChannelEnabled:(BOOL) enable;
44 | -(void) unlockChannelMenuButton;
45 |
46 | -(void) invokeChannelWith:(NSInteger) cid andTitle:(NSString*) title andPlay:(BOOL)playImmediately;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMVolumeSlideCell/DMVolumeSlideCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMVolumeSlideCell.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-24.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DMVolumeSlideCell : NSSliderCell {
12 | NSImage* backImage;
13 | NSImage* sliderImage;
14 | NSRect sliderRect;
15 | NSRect sliderDrawingRect;
16 | NSRect backFrame;
17 | }
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPanel/DMVolumeSlideCell/DMVolumeSlideCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMVolumeSlideCell.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-24.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMVolumeSlideCell.h"
10 |
11 | @implementation DMVolumeSlideCell
12 |
13 | - (void)awakeFromNib
14 | {
15 | backImage = [NSImage imageNamed:@"volume_back"];
16 | sliderImage = [NSImage imageNamed:@"volume_slider"];
17 |
18 | [backImage setFlipped:YES];
19 | [sliderImage setFlipped:YES];
20 |
21 | sliderRect = NSMakeRect(0, 0, 32, 21);
22 | sliderDrawingRect = NSMakeRect(0, 0, 32, 21);
23 | backFrame = NSMakeRect(0, 0, 250, 21);
24 | }
25 | - (NSRect)knobRectFlipped:(BOOL)flipped
26 | {
27 | sliderDrawingRect.origin.x = (250 - 32 * 2 - 10) * [self floatValue] + 21;
28 | return sliderDrawingRect;
29 | }
30 |
31 | - (void)drawBarInside:(NSRect)aRect flipped:(BOOL)flipped
32 | {
33 | [backImage drawInRect:backFrame
34 | fromRect:backFrame
35 | operation:NSCompositeSourceOver
36 | fraction:1.0];
37 | }
38 |
39 | - (void)drawKnob:(NSRect)knobRect
40 | {
41 | CGFloat midX = NSMidX(knobRect);
42 | sliderDrawingRect.origin.x = midX - 16;
43 | [sliderImage drawInRect:knobRect
44 | fromRect:sliderRect
45 | operation:NSCompositeSourceOver
46 | fraction:1.0];
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/diumoo/ui/DMPrefsPanel/DMPrefsPanelDataProvider.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMPrefsPanelDataProvider.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-6-16.
6 | // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "DMShortcutsHandler.h"
10 | #import "MASShortcutView.h"
11 | #import "PLTabPreferenceControl.h"
12 | #import
13 |
14 | #define PANEL_VIEW_COUNT 5
15 |
16 | #define GENERAL_PANEL_ID 0
17 | #define ACCOUNT_PANEL_ID 1
18 | #define KEYBINDINGS_PANNEL_ID 2
19 | #define SPACE_PANEL_ID 3
20 | #define INFO_PANEL_ID 4
21 |
22 | @interface DMPrefsPanelDataProvider : NSObject {
23 | // tab controller ( file owner )
24 | IBOutlet PLTabPreferenceControl* tabcontroller;
25 |
26 | //-----------view outlet -----------
27 | IBOutlet NSView* general;
28 | IBOutlet NSView* login;
29 | IBOutlet NSView* account;
30 | IBOutlet NSView* keybindings;
31 | IBOutlet NSView* info;
32 | IBOutlet NSView* diumoohelper;
33 | //----------------------------------
34 |
35 | //------- General view outlet ------
36 | IBOutlet NSButton* forceGrowl;
37 | IBOutlet NSPopUpButton* muiscQuality;
38 |
39 | //------- login view outlet --------
40 | IBOutlet NSProgressIndicator* indicator;
41 | IBOutlet NSProgressIndicator* loginIndicator;
42 | IBOutlet NSButton* captchaButton;
43 | IBOutlet NSButton* submitButton;
44 | IBOutlet NSButton* resetButton;
45 | IBOutlet NSTextField* email;
46 | IBOutlet NSSecureTextField* password;
47 | IBOutlet NSTextField* captcha;
48 | IBOutlet NSTextField* errorLabel;
49 | //----------------------------------
50 |
51 | //------ account view outlet -------
52 | IBOutlet NSButton* userIconButton;
53 | IBOutlet NSTextField* usernameTextField;
54 | //----------------------------------
55 |
56 | //------ key bindings outlet -------
57 | IBOutlet MASShortcutView* playShortcut;
58 | IBOutlet MASShortcutView* skipShortcut;
59 | IBOutlet MASShortcutView* rateShortcut;
60 | IBOutlet MASShortcutView* banShortcut;
61 | IBOutlet MASShortcutView* togglePanelShortcut;
62 | IBOutlet MASShortcutView* showPrefsPanel;
63 |
64 | //------ info outlet ---------------
65 | IBOutlet NSTextField* displayName;
66 | IBOutlet NSTextField* version;
67 | IBOutlet NSTextField* developer;
68 | }
69 |
70 | @property (copy) NSString* captcha_code;
71 |
72 | - (IBAction)loginAction:(id)sender;
73 | - (IBAction)logoutAction:(id)sender;
74 | - (IBAction)donation:(id)sender;
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/diumoo/ui/DMSearchPanel/DMSearchItemView.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMSearchItemView.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-10-21.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface DMSearchCollectionView : NSCollectionView
12 | @property (nonatomic, unsafe_unretained) id target;
13 | - (NSManagedObject*)selectedItem;
14 | @end
15 |
16 | @interface DMSearchCollectionViewItem : NSCollectionViewItem
17 |
18 | @end
19 |
20 | @interface DMSearchItemView : NSView
21 | @property (readwrite) BOOL selected;
22 | @end
23 |
--------------------------------------------------------------------------------
/diumoo/ui/DMSearchPanel/DMSearchItemView.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMSearchItemView.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-10-21.
6 | //
7 | //
8 |
9 | #import "DMSearchItemView.h"
10 |
11 | @implementation DMSearchCollectionView
12 | @synthesize target;
13 |
14 | - (void)mouseDown:(NSEvent*)theEvent
15 | {
16 | [super mouseDown:theEvent];
17 |
18 | if (theEvent.clickCount == 2) {
19 | NSManagedObject* songObject = [self selectedItem];
20 | if (songObject) {
21 |
22 | NSString* sid = [songObject valueForKey:@"sid"];
23 | NSString* ssid = [songObject valueForKey:@"ssid"];
24 | NSString* start = [NSString stringWithFormat:@"%@g%@g0", sid, ssid];
25 |
26 | NSDictionary* info = @{
27 | @"type" : @"song",
28 | @"start" : start
29 | };
30 |
31 | [[NSNotificationCenter defaultCenter]
32 | postNotificationName:@"playspecial"
33 | object:self
34 | userInfo:info];
35 | }
36 | }
37 | }
38 |
39 | - (NSManagedObject*)selectedItem
40 | {
41 | if ([[self selectionIndexes] count]) {
42 | NSCollectionViewItem* selectedItem = [self itemAtIndex:
43 | [[self selectionIndexes] firstIndex]];
44 | return selectedItem.representedObject;
45 | }
46 | else
47 | return nil;
48 | }
49 |
50 | @end
51 |
52 | @implementation DMSearchCollectionViewItem
53 | - (void)setSelected:(BOOL)selected
54 | {
55 | [super setSelected:selected];
56 | [(DMSearchItemView*)self.view setSelected:selected];
57 | [self.view setNeedsDisplay:YES];
58 | }
59 | @end
60 |
61 | @implementation DMSearchItemView
62 |
63 | - (id)initWithFrame:(NSRect)frame
64 | {
65 | self = [super initWithFrame:frame];
66 | if (self) {
67 | // Initialization code here.
68 | }
69 |
70 | return self;
71 | }
72 |
73 | - (void)drawRect:(NSRect)dirtyRect
74 | {
75 | if (self.selected) {
76 | [[NSColor colorWithCalibratedRed:0.75 green:1.0 blue:0.75 alpha:1.0] setFill];
77 | NSRectFill([self bounds]);
78 | }
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/diumoo/ui/DMSearchPanel/DMSearchPanelController.h:
--------------------------------------------------------------------------------
1 | //
2 | // DMSearchPanelControllerWindowController.h
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-10-9.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface DMSearchPanelController : NSWindowController
12 | @property (readonly) NSManagedObjectContext* contextObject;
13 |
14 | + (DMSearchPanelController*)sharedSearchPanel;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/diumoo/ui/DMSearchPanel/DMSearchPanelController.m:
--------------------------------------------------------------------------------
1 | //
2 | // DMSearchPanelControllerWindowController.m
3 | // diumoo
4 | //
5 | // Created by Shanzi on 12-10-9.
6 | //
7 | //
8 |
9 | #import "DMPlayRecordHandler.h"
10 | #import "DMSearchItemView.h"
11 | #import "DMSearchPanelController.h"
12 |
13 | static DMSearchPanelController* sharedSearchPanel;
14 |
15 | @interface DMSearchPanelController () {
16 | IBOutlet DMSearchCollectionView* collectionview;
17 | IBOutlet NSArrayController* arrayController;
18 | }
19 | @end
20 |
21 | @implementation DMSearchPanelController
22 |
23 | - (id)init
24 | {
25 | self = [super initWithWindowNibName:@"DMSearchPanelController"];
26 | if (self) {
27 | }
28 |
29 | return self;
30 | }
31 |
32 | - (void)windowDidLoad
33 | {
34 | [super windowDidLoad];
35 | [self.window setLevel:NSModalPanelWindowLevel];
36 | [arrayController setValue:@[
37 | [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]
38 | ]
39 | forKey:@"sortDescriptors"];
40 | }
41 |
42 | + (DMSearchPanelController*)sharedSearchPanel
43 | {
44 | if (sharedSearchPanel)
45 | return sharedSearchPanel;
46 | else {
47 | sharedSearchPanel = [[DMSearchPanelController alloc] init];
48 | return sharedSearchPanel;
49 | }
50 | }
51 |
52 | - (NSManagedObjectContext*)contextObject
53 | {
54 | return [DMPlayRecordHandler sharedRecordHandler].context;
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/diumoo/ui/DockIcon/DockImageProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DockImageProvider.swift
3 | // diumoo
4 | //
5 | // Created by leave on 22/12/2017.
6 | //
7 |
8 | import AppKit
9 |
10 | class DockImageProvider {
11 |
12 | static func albumImage(from playableItem: DMPlayableItem) -> NSImage? {
13 | if playableItem.isUsingDefaultFailedAlbumPhoto {
14 | return nil
15 | }
16 | return self.processedImage(playableItem.cover)
17 | }
18 |
19 | private static func processedImage(_ image: NSImage?) -> NSImage? {
20 | guard let image = image else {
21 | return nil
22 | }
23 |
24 | let edge = min(image.size.height, image.size.width, 100)
25 | let radius = 0.2 * edge
26 | let margin = 0.05 * edge
27 | return image.resizeImage(to: CGSize(width: edge, height: edge),
28 | radius: radius,
29 | margin: margin)
30 | }
31 |
32 | }
33 |
34 | extension NSImage {
35 |
36 | fileprivate func resizeImage(to size: CGSize, radius: CGFloat, margin: CGFloat) -> NSImage {
37 | let newImage = NSImage(size: size)
38 | newImage.lockFocus()
39 |
40 | var visiableRect = NSRect.zero
41 | let originalSize = self.size
42 | if originalSize.height > originalSize.width {
43 | visiableRect.origin.x = 0
44 | visiableRect.origin.y = (originalSize.height - originalSize.width) / 2
45 | visiableRect.size.width = originalSize.width
46 | visiableRect.size.height = originalSize.width
47 | } else {
48 | visiableRect.origin.y = 0
49 | visiableRect.origin.x = (originalSize.width - originalSize.height) / 2
50 | visiableRect.size.width = originalSize.height
51 | visiableRect.size.height = originalSize.height
52 | }
53 |
54 | let ctx = NSGraphicsContext.current()
55 | ctx?.imageInterpolation = .high
56 | let imageFrame = NSRect(x: margin, y: margin, width: size.width-margin*2, height: size.height-margin*2)
57 |
58 | let backShape = NSBezierPath(roundedRect: imageFrame.insetBy(dx: -margin*0.5, dy: -margin*0.5)
59 | , xRadius: radius*1.1, yRadius: radius*1.1)
60 | NSColor.white.set()
61 | backShape.fill()
62 |
63 | let clipPath = NSBezierPath(roundedRect: imageFrame, xRadius: radius, yRadius: radius)
64 | clipPath.windingRule = .evenOddWindingRule
65 | clipPath.addClip()
66 |
67 |
68 | self.draw(in: imageFrame,
69 | from: visiableRect,
70 | operation: .copy, fraction: 1)
71 | newImage.unlockFocus()
72 | return newImage
73 | }
74 |
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/diumoo/zh-Hans.lproj/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470
2 | {\fonttbl\f0\fnil\fcharset134 STHeitiSC-Light;\f1\fswiss\fcharset0 Helvetica;\f2\fswiss\fcharset0 ArialMT;
3 | }
4 | {\colortbl;\red255\green255\blue255;\red63\green0\blue63;}
5 | \paperw11905\paperh16837\vieww9600\viewh8400\viewkind0
6 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
7 |
8 | \f0\b\fs24 \cf0 \'bf\'aa\'b7\'a2
9 | \f1 :
10 | \b0 \
11 | ant_sz, Anakin(Yancheng Zheng)\
12 | \
13 |
14 | \f0\b \'bd\'e7\'c3\'e6\'c9\'e8\'bc\'c6
15 | \f1 :
16 | \b0 \
17 |
18 | \f2\fs28 \cf2 chumsdock
19 | \f0 ,
20 | \f1\fs24 \cf0 ant_sz\
21 | \
22 | \
23 | \
24 | }
--------------------------------------------------------------------------------
/diumoo/zh-Hans.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/diumoo/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /* No comment provided by engineer. */
2 | "PLAY_ALBUM_FAILED" = "播放专辑失败";
3 |
4 | /* No comment provided by engineer. */
5 | "PLAY_ALBUM_FAILED_DETAIL" = "没能成功播放您指定的专辑";
6 |
7 | /* No comment provided by engineer. */
8 | "PRIVATE_MHZ" = "私人兆赫";
9 |
10 | /* No comment provided by engineer. */
11 | "SOUNDTRACK_MHZ" = "电影原声";
12 |
13 | /* No comment provided by engineer. */
14 | "EXPORT" = "导出";
15 |
16 | /* No comment provided by engineer. */
17 | "EXPORT_PLAY_RECORD" = "导出播放历史";
18 |
19 | /* No comment provided by engineer. */
20 | "IMPORT" = "导入";
21 |
22 | /* 导入失败 */
23 | "IMPORT_FAILED" = "导入失败";
24 |
25 | /* 导入播放记录失败,您试图导入的文件类型不正确或者文件已损坏。 */
26 | "IMPORT_FAILED_DETAIL" = "导入播放历史失败,您试图导入的文件类型不正确或文件已损坏";
27 |
28 | /* 导入播放记录 */
29 | "IMPORT_PLAY_RECORD" = "导入播放记录";
30 |
31 | /* No comment provided by engineer. */
32 | "OPEN_URL_FAILED" = "打开 URL 失败";
33 |
34 | /* 未能成功打开您指定的URL,可能是您试图播放的专辑、音乐家或电影原声不可用。 */
35 | "OPEN_URL_FAILED_DETAIL" = "未能成功打开您指定的 URL ,可能是您试图播放的专辑、音乐家或电影原声不可用。";
36 |
37 | /* 查看详细 */
38 | "SHOW_DETAIL" = "查看详细";
39 |
40 | /* No comment provided by engineer. */
41 | "SUCCESS_EXPORT" = "成功导出";
42 |
43 | /* 成功导出 %ld 首歌曲的播放记录。 */
44 | "SUCCESS_EXPORT_DETAIL" = "成功导出 %ld 首歌曲的播放记录。";
45 |
46 | /* No comment provided by engineer. */
47 | "SUCCESS_IMPORT" = "成功导入";
48 |
49 | /* 成功导入了 %ld 个歌曲记录,失败 %ld 个。 */
50 | "SUCCESS_IMPORT_DETAIL" = "成功导入了 %ld 个歌曲记录,失败 %ld 个。";
51 |
52 | /* No comment provided by engineer. */
53 | "IMPORT_PLAY_RECORD" = "导入播放历史";
54 |
55 | /* No comment provided by engineer. */
56 | "IMPORT_PLAY_RECORD_DETAIL" = "您刚刚打开的一个diumoo播放记录文件,是否导入这些记录?";
57 |
58 | /* No comment provided by engineer. */
59 | "NO" = "否";
60 |
61 | /* No comment provided by engineer. */
62 | "OPEN_FILE_FAILED" = "打开文件失败";
63 |
64 | /* No comment provided by engineer. */
65 | "YES" = "是";
66 |
67 | /* public */
68 | "LOCALIZED_PUBLIC_LIST_NAME" = "public";
69 |
70 | /* 发生网络错误,请尝试重启应用 */
71 | "NETWORK_ERROR_INDICADTE_STRING"="连接超时,请尝试重启应用";
72 |
73 | /* 专辑:《%@》 */
74 | "ALBUM_DOCUMENT_TITLE" = "专辑:《%@》";
75 |
76 | /* 专辑名 */
77 | "DETAIL_ALBUM" = "专辑名";
78 |
79 | /* 唱片数 */
80 | "DETAIL_DISCS" = "唱片数";
81 |
82 | /* 豆瓣评分 */
83 | "DETAIL_DOUBAN_RATING" = "豆瓣评分";
84 |
85 | /* 条形码 */
86 | "DETAIL_EAN" = "条形码";
87 |
88 | /* 介质 */
89 | "DETAIL_MEDIA" = "介质";
90 |
91 | /* 发行时间 */
92 | "DETAIL_PUBDATE" = "发行时间";
93 |
94 | /* 出版者 */
95 | "DETAIL_PUBLISHER" = "出版者";
96 |
97 | /* %@ (%@ 人评价) */
98 | "DETAIL_RATES" = "%@ (%@ 人评分)";
99 |
100 | /* 歌手 */
101 | "DETAIL_SINGER" = "歌手";
102 |
103 | /* 版本特性 */
104 | "DETAIL_VERSION" = "版本特性";
105 |
106 | /* 获取详细信息失败 */
107 | "GET_DETAIL_FAILED" = "获取详细信息失败";
108 |
109 | /* 解析信息失败 */
110 | "PARSE_DETAIL_FAILED" = "解析信息失败";
111 |
112 | /* 解析信息成功! */
113 | "PARSE_DETAIL_SUCCESS" = "解析信息成功";
114 |
115 | /* 简介 */
116 | "DETAIL_ABSTRACT" = "简介";
117 |
118 | /* 专辑信息 */
119 | "DETAIL_ALBUM_INFO" = "专辑信息";
120 |
121 | /* 曲目 */
122 | "DETAIL_SONGS" = "曲目";
123 |
124 | /* 未知 */
125 | "DETAIL_UNKNOWN" = "未知";
126 |
127 | /* 需要验证码 */
128 | "INVALID_CAPTCHA_CODE" = "未获取验证码";
129 |
130 | /* 验证码不能为空 */
131 | "CAPTCHA_MUST_NOT_BE_EMPTY" = "验证码不能为空";
132 |
133 | /* 邮箱不能为空 */
134 | "EMAIL_MUST_NOT_BE_EMPTY" = "电子邮件不能为空";
135 |
136 | /* 获取失败,请重试 */
137 | "FETCH_CAPTCHA_FAILED" = "获取失败,请重试";
138 |
139 | /* 登陆失败! */
140 | "LOGIN_FAILED" = "登陆失败!";
141 |
142 | /* 密码不能为空 */
143 | "PASSWORD_MUST_NOT_BE_EMPTY" = "密码不能为空";
144 |
145 | /* 关于 */
146 | "PREF_ABOUT" = "关于";
147 |
148 | /* 账户 */
149 | "PREF_ACCOUNT" = "账号";
150 |
151 | /* 通用 */
152 | "PREF_GENERAL" = "通用";
153 |
154 | /* 快捷键 */
155 | "PREF_SHORTCUTS" = "快捷键";
156 |
157 | /* 详细信息 */
158 | "DETAIL" = "详细信息";
159 |
160 | /* 预览 */
161 | "PREVIEW" = "预览";
162 |
163 | /* 豆瓣FM PRO */
164 | "PRO_NEED_BUY_TITLE" = "豆瓣FM Pro";
165 |
166 | /* 豆瓣FM PRO 说明 */
167 | "PRO_NEED_BUY" = "您只有在豆瓣购买了豆瓣FM Pro 的用户才能收听更高音质的音乐。\n\n豆瓣FM Pro 服务由豆瓣官方提供,与 diumoo 无直接联系。\n\n您想要打开豆瓣FM Pro的购买页面么?";
168 |
169 | /* 音乐比特率改变 */
170 | "BITRATE_CHANGED" = "音乐比特率改变";
171 |
172 | /* 音乐比特率改变到 */
173 | "BITRATE_CHANGED_TO_VALUE" = "当前音乐的比特率为:";
174 |
175 | /* 分享链接已复制 */
176 | "SHARE_LINK_TITLE" = "分享链接已复制";
177 |
178 |
--------------------------------------------------------------------------------
/extern/PLTabPreference/PLTabPreferenceControl.h:
--------------------------------------------------------------------------------
1 | //
2 | // PLTabPreferenceControl.h
3 | // PLTabPreferencePanel
4 | //
5 | // Created by xhan on 3/23/11.
6 | // Copyright 2011 Baidu.com. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @protocol PLTabPreferenceDelegate;
13 |
14 | @interface PLTabPreferenceControl : NSWindowController
15 | {
16 | @private
17 | NSToolbar *toolbar;
18 | NSArray* prefIdentifyAry;
19 | id __strong delegate;
20 | }
21 |
22 | @property(nonatomic,strong) IBOutlet id delegate;
23 |
24 | +(PLTabPreferenceControl*) sharedPreferenceController;
25 | +(void) showPrefsAtIndex:(NSInteger) index;
26 |
27 | - (void)selectPanelAtIndex:(NSInteger)index;
28 |
29 | @end
30 |
31 |
32 | @protocol PLTabPreferenceDelegate
33 |
34 | @required
35 |
36 | - (int)countOfPreferencePanels;
37 | - (NSString*)titleForPreferencePanelAt:(NSInteger)index;
38 | - (NSImage*)imageForPreferencePanelAt:(NSInteger)index;
39 | - (NSView*)panelViewForPreferencePanelAt:(NSInteger)index;
40 |
41 | @optional
42 | - (NSString*)identifyForPreferencePanelAt:(NSInteger)index;
43 | - (void)prefViewWillAppear:(NSView*)view atIndex:(NSInteger)index;
44 | - (void)prefViewDidAppear:(NSView*)view atIndex:(NSInteger)index;
45 | @end
--------------------------------------------------------------------------------
/extern/PLTabPreference/PLTabPreferenceControl.m:
--------------------------------------------------------------------------------
1 | //
2 | // PLTabPreferenceControl.m
3 | // PLTabPreferencePanel
4 | //
5 | // Created by xhan on 3/23/11.
6 | // Copyright 2011 Baidu.com. All rights reserved.
7 | //
8 |
9 |
10 | #import "PLTabPreferenceControl.h"
11 |
12 | static PLTabPreferenceControl* shared;
13 |
14 | @interface PLTabPreferenceControl()
15 | - (void)switchPanel:(id)sender;
16 | @end
17 |
18 |
19 | @implementation PLTabPreferenceControl
20 | @synthesize delegate;
21 |
22 |
23 | +(PLTabPreferenceControl*) sharedPreferenceController
24 | {
25 | if (shared) {
26 | return shared;
27 | }
28 | else {
29 | shared = [[PLTabPreferenceControl alloc] initWithWindowNibName:@"DMPrefsPanel"];
30 | return shared;
31 | }
32 | }
33 |
34 | +(void)showPrefsAtIndex:(NSInteger)index
35 | {
36 | [PLTabPreferenceControl sharedPreferenceController];
37 | [shared showWindow:nil];
38 | [shared selectPanelAtIndex:index];
39 | [NSApp activateIgnoringOtherApps:YES];
40 | }
41 |
42 |
43 | - (id)initWithWindow:(NSWindow *)window
44 | {
45 | self = [super initWithWindow:window];
46 | if (self) {
47 | // Initialization code here.
48 | }
49 |
50 | return self;
51 | }
52 |
53 |
54 | - (void)windowDidLoad
55 | {
56 | [super windowDidLoad];
57 | }
58 |
59 |
60 | - (void)awakeFromNib{
61 |
62 | NSWindow* theWin = [self window];
63 |
64 | [theWin setShowsToolbarButton:NO];
65 | // [theWin setShowsResizeIndicator:NO];
66 |
67 | toolbar = [[NSToolbar alloc] initWithIdentifier:NSStringFromClass([self class])];
68 | [toolbar setAllowsUserCustomization:NO];
69 | [toolbar setShowsBaselineSeparator:YES];
70 | [toolbar setDelegate:self];
71 | [[self window] setToolbar:toolbar];
72 |
73 | // [toolbar validateVisibleItems];
74 |
75 | [self selectPanelAtIndex:0];
76 | }
77 |
78 | /////////////////////////////////////////////
79 | #pragma TabPreference methods
80 | - (void)switchPanel:(id)sender
81 | {
82 | NSView *viewToShow = [delegate panelViewForPreferencePanelAt:(NSInteger)[sender tag]];
83 | NSWindow* theWin = [self window];
84 |
85 |
86 | if (viewToShow && ([theWin contentView] != viewToShow.superview)) {
87 |
88 | for (NSView*v in [[theWin contentView] subviews]) {
89 | [v removeFromSuperview];
90 | }
91 |
92 | viewToShow.alphaValue = 0;
93 |
94 | //will appear
95 | if ([delegate respondsToSelector:@selector(prefViewWillAppear:atIndex:)]) {
96 | [delegate prefViewWillAppear:viewToShow atIndex:[sender tag]];
97 | }
98 |
99 | [toolbar setSelectedItemIdentifier:[sender itemIdentifier]];
100 |
101 | NSRect newFrame = [theWin frameRectForContentRect:[viewToShow bounds]];
102 | NSRect oldFrame = [theWin frame];
103 |
104 | newFrame.origin = oldFrame.origin;
105 | newFrame.origin.y -= (newFrame.size.height - oldFrame.size.height);
106 | [[theWin contentView] addSubview:viewToShow];
107 |
108 |
109 |
110 |
111 | [theWin setFrame:newFrame display:YES animate:YES];
112 | [viewToShow.animator setAlphaValue:1.0];
113 |
114 | [theWin setTitle:[sender label]];
115 |
116 |
117 | if ([delegate respondsToSelector:@selector(prefViewDidAppear:atIndex:)]) {
118 | [delegate prefViewDidAppear:viewToShow atIndex:[sender tag]];
119 | }
120 |
121 | }
122 | }
123 |
124 | - (void)selectPanelAtIndex:(NSInteger)index
125 | {
126 | NSToolbarItem* item = [toolbar items][index];
127 | if (item) {
128 | [self switchPanel:item];
129 | }
130 | }
131 |
132 | /////////////////////////////////////////////
133 | #pragma toolbar delegates
134 | - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
135 | {
136 | if (prefIdentifyAry) {
137 | return prefIdentifyAry;
138 | }
139 | if (self.delegate) {
140 | NSInteger count = [self.delegate countOfPreferencePanels];
141 | NSMutableArray* array = [NSMutableArray arrayWithCapacity:count];
142 | for (NSInteger i = 0; i< count; i++) {
143 | NSString* identify;
144 | if ([delegate respondsToSelector:@selector(identifyForPreferencePanelAt:)]) {
145 | identify = [delegate identifyForPreferencePanelAt:i];
146 | }else{
147 | identify = [NSString stringWithFormat:@"%ld",i];
148 | }
149 | [array addObject:identify];
150 | }
151 | prefIdentifyAry = [[NSArray alloc] initWithArray:array];
152 | return prefIdentifyAry;
153 | }
154 | return nil;
155 | }
156 |
157 | - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)atoolbar
158 | {
159 | return [self toolbarAllowedItemIdentifiers:toolbar];
160 | }
161 | - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)atoolbar
162 | {
163 | return [self toolbarAllowedItemIdentifiers:toolbar];
164 | }
165 |
166 | - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
167 | {
168 |
169 | NSUInteger index = [prefIdentifyAry indexOfObject:itemIdentifier];
170 | if (index == NSNotFound) {
171 | return nil;
172 | }
173 | NSToolbarItem *item = nil;
174 |
175 | item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
176 | [item setLabel:[delegate titleForPreferencePanelAt:(NSInteger)index]];
177 | [item setImage:[delegate imageForPreferencePanelAt:(NSInteger)index]];
178 | [item setTag:index];
179 |
180 | [item setTarget:self];
181 | [item setAction:@selector(switchPanel:)];
182 | [item setAutovalidates:NO];
183 |
184 | return item;
185 | }
186 |
187 |
188 | @end
189 |
--------------------------------------------------------------------------------
/extern/SSKeychain/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010-2011 Sam Soffes.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/extern/SSKeychain/SSKeychain.m:
--------------------------------------------------------------------------------
1 | //
2 | // SSKeychain.m
3 | // SSToolkit
4 | //
5 | // Created by Sam Soffes on 5/19/10.
6 | // Copyright (c) 2009-2011 Sam Soffes. All rights reserved.
7 | //
8 |
9 | #import "SSKeychain.h"
10 |
11 | NSString *const kSSKeychainErrorDomain = @"com.samsoffes.sskeychain";
12 |
13 | NSString *const kSSKeychainAccountKey = @"acct";
14 | NSString *const kSSKeychainCreatedAtKey = @"cdat";
15 | NSString *const kSSKeychainClassKey = @"labl";
16 | NSString *const kSSKeychainDescriptionKey = @"desc";
17 | NSString *const kSSKeychainLabelKey = @"labl";
18 | NSString *const kSSKeychainLastModifiedKey = @"mdat";
19 | NSString *const kSSKeychainWhereKey = @"svce";
20 |
21 | #if __IPHONE_4_0 && TARGET_OS_IPHONE
22 | CFTypeRef SSKeychainAccessibilityType = NULL;
23 | #endif
24 |
25 | @interface SSKeychain ()
26 | + (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account;
27 | @end
28 |
29 | @implementation SSKeychain
30 |
31 | #pragma mark - Getting Accounts
32 |
33 | + (NSArray *)allAccounts {
34 | return [self accountsForService:nil error:nil];
35 | }
36 |
37 |
38 | + (NSArray *)allAccounts:(NSError **)error {
39 | return [self accountsForService:nil error:error];
40 | }
41 |
42 |
43 | + (NSArray *)accountsForService:(NSString *)service {
44 | return [self accountsForService:service error:nil];
45 | }
46 |
47 |
48 | + (NSArray *)accountsForService:(NSString *)service error:(NSError **)error {
49 | OSStatus status = SSKeychainErrorBadArguments;
50 | NSMutableDictionary *query = [self _queryForService:service account:nil];
51 | #if __has_feature(objc_arc)
52 | [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
53 | [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
54 | #else
55 | query[(id)kSecReturnAttributes] = (id)kCFBooleanTrue;
56 | query[(id)kSecMatchLimit] = (id)kSecMatchLimitAll;
57 | #endif
58 |
59 | CFTypeRef result = NULL;
60 | #if __has_feature(objc_arc)
61 | status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
62 | #else
63 | status = SecItemCopyMatching((CFDictionaryRef)query, &result);
64 | #endif
65 | if (status != noErr && error != NULL) {
66 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
67 | return nil;
68 | }
69 |
70 | #if __has_feature(objc_arc)
71 | return (__bridge_transfer NSArray *)result;
72 | #else
73 | return [(NSArray *)result autorelease];
74 | #endif
75 | }
76 |
77 |
78 | #pragma mark - Getting Passwords
79 |
80 | + (NSString *)passwordForService:(NSString *)service account:(NSString *)account {
81 | return [self passwordForService:service account:account error:nil];
82 | }
83 |
84 |
85 | + (NSString *)passwordForService:(NSString *)service account:(NSString *)account error:(NSError **)error {
86 | NSData *data = [self passwordDataForService:service account:account error:error];
87 | if (data.length > 0) {
88 | NSString *string = [[NSString alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding];
89 | #if !__has_feature(objc_arc)
90 | [string autorelease];
91 | #endif
92 | return string;
93 | }
94 |
95 | return nil;
96 | }
97 |
98 |
99 | + (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account {
100 | return [self passwordDataForService:service account:account error:nil];
101 | }
102 |
103 |
104 | + (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account error:(NSError **)error {
105 | OSStatus status = SSKeychainErrorBadArguments;
106 | if (!service || !account) {
107 | if (error) {
108 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
109 | }
110 | return nil;
111 | }
112 |
113 | CFTypeRef result = NULL;
114 | NSMutableDictionary *query = [self _queryForService:service account:account];
115 | #if __has_feature(objc_arc)
116 | [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
117 | [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
118 | status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
119 | #else
120 | query[(id)kSecReturnData] = (id)kCFBooleanTrue;
121 | query[(id)kSecMatchLimit] = (id)kSecMatchLimitOne;
122 | status = SecItemCopyMatching((CFDictionaryRef)query, &result);
123 | #endif
124 |
125 | if (status != noErr && error != NULL) {
126 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
127 | return nil;
128 | }
129 |
130 | #if __has_feature(objc_arc)
131 | return (__bridge_transfer NSData *)result;
132 | #else
133 | return [(NSData *)result autorelease];
134 | #endif
135 | }
136 |
137 |
138 | #pragma mark - Deleting Passwords
139 |
140 | + (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account {
141 | return [self deletePasswordForService:service account:account error:nil];
142 | }
143 |
144 |
145 | + (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account error:(NSError **)error {
146 | OSStatus status = SSKeychainErrorBadArguments;
147 | if (service && account) {
148 | NSMutableDictionary *query = [self _queryForService:service account:account];
149 | #if __has_feature(objc_arc)
150 | status = SecItemDelete((__bridge CFDictionaryRef)query);
151 | #else
152 | status = SecItemDelete((CFDictionaryRef)query);
153 | #endif
154 | }
155 | if (status != noErr && error != NULL) {
156 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
157 | }
158 | return (status == noErr);
159 |
160 | }
161 |
162 |
163 | #pragma mark - Setting Passwords
164 |
165 | + (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account {
166 | return [self setPassword:password forService:service account:account error:nil];
167 | }
168 |
169 |
170 | + (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error {
171 | NSData *data = [password dataUsingEncoding:NSUTF8StringEncoding];
172 | return [self setPasswordData:data forService:service account:account error:error];
173 | }
174 |
175 |
176 | + (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account {
177 | return [self setPasswordData:password forService:service account:account error:nil];
178 | }
179 |
180 |
181 | + (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error {
182 | OSStatus status = SSKeychainErrorBadArguments;
183 | if (password && service && account) {
184 | [self deletePasswordForService:service account:account];
185 | NSMutableDictionary *query = [self _queryForService:service account:account];
186 | #if __has_feature(objc_arc)
187 | [query setObject:password forKey:(__bridge id)kSecValueData];
188 | #else
189 | query[(id)kSecValueData] = password;
190 | #endif
191 |
192 | #if __IPHONE_4_0 && TARGET_OS_IPHONE
193 | if (SSKeychainAccessibilityType) {
194 | #if __has_feature(objc_arc)
195 | [query setObject:(id)[self accessibilityType] forKey:(__bridge id)kSecAttrAccessible];
196 | #else
197 | [query setObject:(id)[self accessibilityType] forKey:(id)kSecAttrAccessible];
198 | #endif
199 | }
200 | #endif
201 |
202 | #if __has_feature(objc_arc)
203 | status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
204 | #else
205 | status = SecItemAdd((CFDictionaryRef)query, NULL);
206 | #endif
207 | }
208 | if (status != noErr && error != NULL) {
209 | *error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
210 | }
211 | return (status == noErr);
212 | }
213 |
214 |
215 | #pragma mark - Configuration
216 |
217 | #if __IPHONE_4_0 && TARGET_OS_IPHONE
218 | + (CFTypeRef)accessibilityType {
219 | return SSKeychainAccessibilityType;
220 | }
221 |
222 |
223 | + (void)setAccessibilityType:(CFTypeRef)accessibilityType {
224 | CFRetain(accessibilityType);
225 | if (SSKeychainAccessibilityType) {
226 | CFRelease(SSKeychainAccessibilityType);
227 | }
228 | SSKeychainAccessibilityType = accessibilityType;
229 | }
230 | #endif
231 |
232 |
233 | #pragma mark - Private
234 |
235 | + (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account {
236 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3];
237 | #if __has_feature(objc_arc)
238 | [dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
239 | #else
240 | dictionary[(id)kSecClass] = (id)kSecClassGenericPassword;
241 | #endif
242 |
243 | if (service) {
244 | #if __has_feature(objc_arc)
245 | [dictionary setObject:service forKey:(__bridge id)kSecAttrService];
246 | #else
247 | dictionary[(id)kSecAttrService] = service;
248 | #endif
249 | }
250 |
251 | if (account) {
252 | #if __has_feature(objc_arc)
253 | [dictionary setObject:account forKey:(__bridge id)kSecAttrAccount];
254 | #else
255 | dictionary[(id)kSecAttrAccount] = account;
256 | #endif
257 | }
258 |
259 | return dictionary;
260 | }
261 |
262 | @end
263 |
--------------------------------------------------------------------------------
/extern/StatusItem/MenubarController.h:
--------------------------------------------------------------------------------
1 | #define STATUS_ITEM_VIEW_WIDTH 24.0
2 |
3 | #pragma mark -
4 |
5 | @class StatusItemView;
6 |
7 | @interface MenubarController : NSObject {
8 | @private
9 | StatusItemView *_statusItemView;
10 | }
11 |
12 | @property (nonatomic) BOOL hasActiveIcon;
13 | @property (nonatomic, readonly) StatusItemView *statusItemView;
14 |
15 | - (NSStatusItem *)statusItem;
16 | -(void) setMixed:(BOOL) mixed;
17 | -(void) setAction:(SEL) action withTarget:(id) target;
18 | @end
19 |
--------------------------------------------------------------------------------
/extern/StatusItem/MenubarController.m:
--------------------------------------------------------------------------------
1 | #import "MenubarController.h"
2 | #import "StatusItemView.h"
3 |
4 | @implementation MenubarController
5 |
6 | @synthesize statusItemView = _statusItemView;
7 |
8 | #pragma mark -
9 |
10 | - (id)init
11 | {
12 | if (self = [super init])
13 | {
14 | // Install status item into the menu bar
15 | NSStatusItem *statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:STATUS_ITEM_VIEW_WIDTH];
16 | _statusItemView = [[StatusItemView alloc] initWithStatusItem:statusItem];
17 |
18 | [self setStatusItemImage];
19 |
20 | [[NSDistributedNotificationCenter defaultCenter]
21 | addObserver:self
22 | selector:@selector(setStatusItemImage)
23 | name:@"AppleInterfaceThemeChangedNotification"
24 | object:nil];
25 | }
26 | return self;
27 | }
28 |
29 | - (bool) isDarkMode
30 | {
31 | NSString * interfaceStyle = [[NSUserDefaults standardUserDefaults] stringForKey: @"AppleInterfaceStyle"];
32 | return (interfaceStyle != nil) && [interfaceStyle isEqualToString:@"Dark"];
33 | }
34 |
35 | - (void) setStatusItemImage
36 | {
37 | if ([self isDarkMode]) {
38 | _statusItemView.image = [NSImage imageNamed:@"dark-status-icon"];
39 | _statusItemView.mixedImage = [NSImage imageNamed:@"dark-status-icon-mixed"];
40 | _statusItemView.alternateImage = [NSImage imageNamed:@"dark-status-icon-alt"];
41 | } else {
42 | _statusItemView.image = [NSImage imageNamed:@"status-icon"];
43 | _statusItemView.mixedImage = [NSImage imageNamed:@"status-icon-mixed"];
44 | _statusItemView.alternateImage = [NSImage imageNamed:@"status-icon-alt"];
45 | }
46 | }
47 |
48 | - (void)dealloc
49 | {
50 | [[NSStatusBar systemStatusBar] removeStatusItem:self.statusItem];
51 | }
52 |
53 | #pragma mark -
54 | #pragma mark Public accessors
55 |
56 | - (NSStatusItem *)statusItem
57 | {
58 | return self.statusItemView.statusItem;
59 | }
60 |
61 | -(void) setMixed:(BOOL)mixed
62 | {
63 | [_statusItemView setMixed:mixed];
64 | }
65 |
66 | -(void) setAction:(SEL)action withTarget:(id)target
67 | {
68 | _statusItemView.action = action;
69 | _statusItemView.target = target;
70 | }
71 |
72 | #pragma mark -
73 |
74 | - (BOOL)hasActiveIcon
75 | {
76 | return self.statusItemView.isHighlighted;
77 | }
78 |
79 | - (void)setHasActiveIcon:(BOOL)flag
80 | {
81 | self.statusItemView.isHighlighted = flag;
82 | }
83 |
84 | @end
85 |
--------------------------------------------------------------------------------
/extern/StatusItem/StatusItemView.h:
--------------------------------------------------------------------------------
1 | @interface StatusItemView : NSView {
2 | @private
3 | NSImage *_image;
4 | NSImage *_mixedImage;
5 | NSImage *_alternateImage;
6 | NSStatusItem *_statusItem;
7 | BOOL _isHighlighted;
8 | BOOL _isMixed;
9 | SEL _action;
10 | __unsafe_unretained id _target;
11 | }
12 |
13 | - (id)initWithStatusItem:(NSStatusItem *)statusItem;
14 |
15 | @property (nonatomic, strong, readonly) NSStatusItem *statusItem;
16 | @property (nonatomic, strong) NSImage *image;
17 | @property (nonatomic, strong) NSImage *mixedImage;
18 | @property (nonatomic, strong) NSImage *alternateImage;
19 | @property (nonatomic, setter = setHighlighted:) BOOL isHighlighted;
20 | @property (nonatomic, setter = setMixed:) BOOL isMixed;
21 | @property (nonatomic, readonly) NSRect globalRect;
22 | @property (nonatomic) SEL action;
23 | @property (nonatomic, unsafe_unretained) id target;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/extern/StatusItem/StatusItemView.m:
--------------------------------------------------------------------------------
1 | #import "StatusItemView.h"
2 |
3 | @implementation StatusItemView
4 |
5 | @synthesize statusItem = _statusItem;
6 | @synthesize image = _image;
7 | @synthesize mixedImage = _mixedImage;
8 | @synthesize alternateImage = _alternateImage;
9 | @synthesize isHighlighted = _isHighlighted;
10 | @synthesize isMixed = _isMixed;
11 | @synthesize action = _action;
12 | @synthesize target = _target;
13 |
14 | #pragma mark -
15 |
16 | - (id)initWithStatusItem:(NSStatusItem *)statusItem
17 | {
18 | CGFloat itemWidth = [statusItem length];
19 | CGFloat itemHeight = [[NSStatusBar systemStatusBar] thickness];
20 | NSRect itemRect = NSMakeRect(0.0, 0.0, itemWidth, itemHeight);
21 | self = [super initWithFrame:itemRect];
22 | if (self != nil) {
23 | _statusItem = statusItem;
24 | _statusItem.view = self;
25 | }
26 | return self;
27 | }
28 |
29 |
30 | #pragma mark -
31 |
32 | - (void)drawRect:(NSRect)dirtyRect
33 | {
34 | [self.statusItem drawStatusBarBackgroundInRect:dirtyRect withHighlight:self.isHighlighted];
35 |
36 | NSImage *icon = self.isHighlighted ? self.alternateImage : (self.isMixed ? self.mixedImage:self.image);
37 | NSSize iconSize = [icon size];
38 | NSRect bounds = self.bounds;
39 | CGFloat iconX = roundf((NSWidth(bounds) - iconSize.width) / 2);
40 | CGFloat iconY = roundf((NSHeight(bounds) - iconSize.height) / 2);
41 | NSPoint iconPoint = NSMakePoint(iconX, iconY);
42 | [icon drawAtPoint:iconPoint fromRect:bounds operation:NSCompositeSourceOver fraction:1.0];
43 | }
44 |
45 | #pragma mark -
46 | #pragma mark Mouse tracking
47 |
48 | - (void)mouseDown:(NSEvent *)theEvent
49 | {
50 | [NSApp sendAction:self.action to:self.target from:self];
51 | }
52 |
53 | #pragma mark -
54 | #pragma mark Accessors
55 |
56 | - (void)setHighlighted:(BOOL)newFlag
57 | {
58 | if (_isHighlighted == newFlag) return;
59 | _isHighlighted = newFlag;
60 | [self setNeedsDisplay:YES];
61 | }
62 |
63 | -(void) setMixed:(BOOL)isMixed
64 | {
65 | if (_isMixed == isMixed) {
66 | return;
67 | }
68 | else {
69 | _isMixed = isMixed;
70 | [self setNeedsDisplay:YES];
71 | }
72 | }
73 |
74 | #pragma mark -
75 |
76 | - (void)setImage:(NSImage *)newImage
77 | {
78 | if (_image != newImage) {
79 | _image = newImage;
80 | [self setNeedsDisplay:YES];
81 | }
82 | }
83 |
84 | - (void)setAlternateImage:(NSImage *)newImage
85 | {
86 | if (_alternateImage != newImage) {
87 | _alternateImage = newImage;
88 | if (self.isHighlighted) {
89 | [self setNeedsDisplay:YES];
90 | }
91 | }
92 | }
93 |
94 | #pragma mark -
95 |
96 | - (NSRect)globalRect
97 | {
98 | return [self.window convertRectToScreen:[self frame]];
99 | }
100 |
101 | @end
102 |
--------------------------------------------------------------------------------
/resources/128kbps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/128kbps.png
--------------------------------------------------------------------------------
/resources/128kbps@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/128kbps@2x.png
--------------------------------------------------------------------------------
/resources/192kbps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/192kbps.png
--------------------------------------------------------------------------------
/resources/192kbps@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/192kbps@2x.png
--------------------------------------------------------------------------------
/resources/64kbps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/64kbps.png
--------------------------------------------------------------------------------
/resources/64kbps@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/64kbps@2x.png
--------------------------------------------------------------------------------
/resources/albumfail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/albumfail.png
--------------------------------------------------------------------------------
/resources/albumfail@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/albumfail@2x.png
--------------------------------------------------------------------------------
/resources/ban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/ban.png
--------------------------------------------------------------------------------
/resources/ban@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/ban@2x.png
--------------------------------------------------------------------------------
/resources/ban_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/ban_mouseover.png
--------------------------------------------------------------------------------
/resources/ban_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/ban_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/chrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/chrome.png
--------------------------------------------------------------------------------
/resources/chrome_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/chrome_2x.png
--------------------------------------------------------------------------------
/resources/dark-status-icon-alt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/dark-status-icon-alt.png
--------------------------------------------------------------------------------
/resources/dark-status-icon-alt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/dark-status-icon-alt@2x.png
--------------------------------------------------------------------------------
/resources/dark-status-icon-mixed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/dark-status-icon-mixed.png
--------------------------------------------------------------------------------
/resources/dark-status-icon-mixed@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/dark-status-icon-mixed@2x.png
--------------------------------------------------------------------------------
/resources/dark-status-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/dark-status-icon.png
--------------------------------------------------------------------------------
/resources/dark-status-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/dark-status-icon@2x.png
--------------------------------------------------------------------------------
/resources/detail_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/detail_icon.png
--------------------------------------------------------------------------------
/resources/detail_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/detail_icon@2x.png
--------------------------------------------------------------------------------
/resources/douban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/douban.png
--------------------------------------------------------------------------------
/resources/douban@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/douban@2x.png
--------------------------------------------------------------------------------
/resources/exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/exit.png
--------------------------------------------------------------------------------
/resources/exit@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/exit@2x.png
--------------------------------------------------------------------------------
/resources/exit_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/exit_mouseover.png
--------------------------------------------------------------------------------
/resources/exit_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/exit_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/eye_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/eye_icon.png
--------------------------------------------------------------------------------
/resources/eye_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/eye_icon@2x.png
--------------------------------------------------------------------------------
/resources/facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/facebook.png
--------------------------------------------------------------------------------
/resources/facebook@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/facebook@2x.png
--------------------------------------------------------------------------------
/resources/fanfou.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/fanfou.png
--------------------------------------------------------------------------------
/resources/fanfou@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/fanfou@2x.png
--------------------------------------------------------------------------------
/resources/firefox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/firefox.png
--------------------------------------------------------------------------------
/resources/firefox_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/firefox_2x.png
--------------------------------------------------------------------------------
/resources/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/icon.icns
--------------------------------------------------------------------------------
/resources/info_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/info_icon.png
--------------------------------------------------------------------------------
/resources/info_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/info_icon@2x.png
--------------------------------------------------------------------------------
/resources/menu-heart-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/menu-heart-gray.png
--------------------------------------------------------------------------------
/resources/menu-heart-gray@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/menu-heart-gray@2x.png
--------------------------------------------------------------------------------
/resources/menu-heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/menu-heart.png
--------------------------------------------------------------------------------
/resources/menu-heart@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/menu-heart@2x.png
--------------------------------------------------------------------------------
/resources/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/pause.png
--------------------------------------------------------------------------------
/resources/pause@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/pause@2x.png
--------------------------------------------------------------------------------
/resources/pause_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/pause_mouseover.png
--------------------------------------------------------------------------------
/resources/pause_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/pause_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/play.png
--------------------------------------------------------------------------------
/resources/play@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/play@2x.png
--------------------------------------------------------------------------------
/resources/play_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/play_mouseover.png
--------------------------------------------------------------------------------
/resources/play_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/play_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/pro_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/pro_icon.png
--------------------------------------------------------------------------------
/resources/pro_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/pro_icon@2x.png
--------------------------------------------------------------------------------
/resources/rate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/rate.png
--------------------------------------------------------------------------------
/resources/rate@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/rate@2x.png
--------------------------------------------------------------------------------
/resources/rate_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/rate_mouseover.png
--------------------------------------------------------------------------------
/resources/rate_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/rate_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/rate_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/rate_red.png
--------------------------------------------------------------------------------
/resources/rate_red@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/rate_red@2x.png
--------------------------------------------------------------------------------
/resources/record.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/record.icns
--------------------------------------------------------------------------------
/resources/safari.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/safari.png
--------------------------------------------------------------------------------
/resources/safari_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/safari_2x.png
--------------------------------------------------------------------------------
/resources/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/search.png
--------------------------------------------------------------------------------
/resources/search@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/search@2x.png
--------------------------------------------------------------------------------
/resources/search_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/search_mouseover.png
--------------------------------------------------------------------------------
/resources/search_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/search_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/settings.png
--------------------------------------------------------------------------------
/resources/settings@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/settings@2x.png
--------------------------------------------------------------------------------
/resources/settings_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/settings_mouseover.png
--------------------------------------------------------------------------------
/resources/settings_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/settings_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/share.png
--------------------------------------------------------------------------------
/resources/share@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/share@2x.png
--------------------------------------------------------------------------------
/resources/sina.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/sina.png
--------------------------------------------------------------------------------
/resources/sina@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/sina@2x.png
--------------------------------------------------------------------------------
/resources/skip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/skip.png
--------------------------------------------------------------------------------
/resources/skip@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/skip@2x.png
--------------------------------------------------------------------------------
/resources/skip_mouseover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/skip_mouseover.png
--------------------------------------------------------------------------------
/resources/skip_mouseover@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/skip_mouseover@2x.png
--------------------------------------------------------------------------------
/resources/status-icon-alt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/status-icon-alt.png
--------------------------------------------------------------------------------
/resources/status-icon-alt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/status-icon-alt@2x.png
--------------------------------------------------------------------------------
/resources/status-icon-mixed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/status-icon-mixed.png
--------------------------------------------------------------------------------
/resources/status-icon-mixed@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/status-icon-mixed@2x.png
--------------------------------------------------------------------------------
/resources/status-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/status-icon.png
--------------------------------------------------------------------------------
/resources/status-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/status-icon@2x.png
--------------------------------------------------------------------------------
/resources/time_machine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/time_machine.png
--------------------------------------------------------------------------------
/resources/time_machine@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/time_machine@2x.png
--------------------------------------------------------------------------------
/resources/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/twitter.png
--------------------------------------------------------------------------------
/resources/twitter@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/twitter@2x.png
--------------------------------------------------------------------------------
/resources/view_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/view_icon.png
--------------------------------------------------------------------------------
/resources/view_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/view_icon@2x.png
--------------------------------------------------------------------------------
/resources/volume_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/volume_back.png
--------------------------------------------------------------------------------
/resources/volume_back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/volume_back@2x.png
--------------------------------------------------------------------------------
/resources/volume_slider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/volume_slider.png
--------------------------------------------------------------------------------
/resources/volume_slider@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanzi/diumoo/cefda3edf61ec2d8c9b5fe314cb0c23e630ea4d6/resources/volume_slider@2x.png
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/NSDictionary+SMKeyValueObserving.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+SMKeyValueObserving.h
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 04.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface NSDictionary (SMKeyValueObserving)
13 |
14 | @property (readonly) NSUInteger keyValueChangeKind;
15 | @property (readonly) id keyValueChangeNew;
16 | @property (readonly) id keyValueChangeOld;
17 | @property (readonly) NSIndexSet *keyValueChangeIndexes;
18 | @property (readonly) BOOL keyValueChanged;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/NSDictionary+SMKeyValueObserving.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+SMKeyValueObserving.m
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 04.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import "NSDictionary+SMKeyValueObserving.h"
10 |
11 |
12 | @implementation NSDictionary (SMKeyValueObserving)
13 |
14 | - (NSUInteger)keyValueChangeKind {
15 | return [[self objectForKey:NSKeyValueChangeKindKey] unsignedIntegerValue];
16 | }
17 |
18 | - (id)keyValueChangeNew {
19 | id value = [self objectForKey:NSKeyValueChangeNewKey];
20 | if ([value isEqual:[NSNull null]]) {
21 | return nil;
22 | }
23 | return value;
24 | }
25 |
26 | - (id)keyValueChangeOld {
27 | id value = [self objectForKey:NSKeyValueChangeOldKey];
28 | if ([value isEqual:[NSNull null]]) {
29 | return nil;
30 | }
31 | return value;
32 | }
33 |
34 | - (NSIndexSet *)keyValueChangeIndexes {
35 | return [self objectForKey:NSKeyValueChangeIndexesKey];
36 | }
37 |
38 | - (BOOL)keyValueChanged {
39 | if ([self keyValueChangeOld] == nil) {
40 | return [self keyValueChangeNew] != nil;
41 | }
42 | return ![[self keyValueChangeNew] isEqual:[self keyValueChangeOld]];
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMBar.h:
--------------------------------------------------------------------------------
1 | //
2 | // SMBar.h
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 12.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SMBar : NSView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMBar.m:
--------------------------------------------------------------------------------
1 | //
2 | // SMBar.m
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 12.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import "SMBar.h"
10 |
11 | @implementation SMBar
12 |
13 | // using app and window notifications to change gradient for inactive windows, see
14 | // http://code.google.com/p/tlanimatingoutlineview/source/browse/trunk/Classes/TLGradientView.m
15 | - (void)viewWillMoveToWindow:(NSWindow *)newWindow {
16 | [super viewWillMoveToWindow:newWindow];
17 |
18 | NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
19 |
20 | NSWindow *oldWindow = self.window;
21 |
22 | if (!oldWindow && newWindow) {
23 | [center addObserver:self selector:@selector(windowDidChange:) name:NSApplicationDidBecomeActiveNotification object:NSApp];
24 | [center addObserver:self selector:@selector(windowDidChange:) name:NSApplicationDidResignActiveNotification object:NSApp];
25 | } else if (oldWindow && !newWindow) {
26 | [center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:NSApp];
27 | [center removeObserver:self name:NSApplicationDidResignActiveNotification object:NSApp];
28 | }
29 |
30 | if (oldWindow) {
31 | [center removeObserver:self name:NSWindowDidResignKeyNotification object:oldWindow];
32 | [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:oldWindow];
33 | }
34 |
35 | if (newWindow) {
36 | [center addObserver:self selector:@selector(windowDidChange:) name:NSWindowDidResignKeyNotification object:newWindow];
37 | [center addObserver:self selector:@selector(windowDidChange:) name:NSWindowDidBecomeKeyNotification object:newWindow];
38 | }
39 | }
40 |
41 | #pragma mark - Drawing
42 |
43 | - (void)drawRect:(CGRect)rect {
44 |
45 | if ([[self window] isKeyWindow]) {
46 | static NSGradient *gradient = nil;
47 | static NSColor *borderColor = nil;
48 | if (!gradient) {
49 | NSColor *color1 = [NSColor colorWithCalibratedWhite:0.851f alpha:1.0f];
50 | NSColor *color2 = [NSColor colorWithCalibratedWhite:0.700f alpha:1.0f];
51 | gradient = [[NSGradient alloc] initWithStartingColor:color1
52 | endingColor:color2];
53 | borderColor = [NSColor colorWithCalibratedWhite:0.416 alpha:1];
54 | }
55 |
56 | // Draw bar gradient
57 | [gradient drawInRect:self.bounds angle:90.0];
58 |
59 | // add noise
60 | [self drawNoisePattern];
61 |
62 | // Draw drak gray bottom border
63 | [borderColor setStroke];
64 | [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMinX(self.bounds), NSMaxY(self.bounds) - 0.5f)
65 | toPoint:NSMakePoint(NSMaxX(self.bounds), NSMaxY(self.bounds) - 0.5f)];
66 | } else {
67 | static NSGradient *gradient = nil;
68 | static NSColor *borderColor = nil;
69 | if (!gradient) {
70 | NSColor *color1 = [NSColor colorWithCalibratedWhite:0.965 alpha:1];
71 | NSColor *color2 = [NSColor colorWithCalibratedWhite:0.851 alpha:1];
72 | gradient = [[NSGradient alloc] initWithStartingColor:color1
73 | endingColor:color2];
74 | borderColor = [NSColor colorWithCalibratedWhite:0.651 alpha:1];
75 | }
76 |
77 | // Draw bar gradient
78 | [gradient drawInRect:self.bounds angle:90.0];
79 |
80 | // add noise
81 | [self drawNoisePattern];
82 |
83 | // Draw drak gray bottom border
84 | [borderColor setStroke];
85 | [NSBezierPath setDefaultLineWidth:0.0f];
86 | [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMinX(self.bounds), NSMaxY(self.bounds) - 0.5f)
87 | toPoint:NSMakePoint(NSMaxX(self.bounds), NSMaxY(self.bounds) - 0.5f)];
88 | }
89 | }
90 |
91 | // add noise pattern, see http://stackoverflow.com/questions/8766239
92 | - (void)drawNoisePattern {
93 | static CGImageRef noisePattern = nil;
94 | if (noisePattern == nil) {
95 | noisePattern = SMNoiseImageCreate(128, 128, 0.015);
96 | }
97 |
98 | [NSGraphicsContext saveGraphicsState];
99 |
100 | [[NSGraphicsContext currentContext] setCompositingOperation:NSCompositePlusLighter];
101 | CGRect noisePatternRect = CGRectMake(0.0f, 0.0f, CGImageGetWidth(noisePattern), CGImageGetHeight(noisePattern));
102 | CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
103 | CGContextDrawTiledImage(context, noisePatternRect, noisePattern);
104 |
105 | [NSGraphicsContext restoreGraphicsState];
106 | }
107 |
108 | static CGImageRef SMNoiseImageCreate(NSUInteger width, NSUInteger height, CGFloat factor) {
109 | NSUInteger size = width * height;
110 | char *rgba = (char *)malloc(size); srand(124);
111 | for(NSUInteger i = 0; i < size; i++) {
112 | rgba[i] = rand() % 256 * factor;
113 | }
114 |
115 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
116 | CGContextRef bitmapContext = CGBitmapContextCreate(rgba, width, height, 8, width, colorSpace, kCGImageAlphaNone);
117 | CFRelease(colorSpace);
118 | free(rgba);
119 |
120 | CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
121 | CFRelease(bitmapContext);
122 |
123 | return image;
124 | }
125 |
126 | - (BOOL)isFlipped {
127 | return YES;
128 | }
129 |
130 | #pragma mark - Notifications
131 |
132 | - (void)windowDidChange:(NSNotification *)notification {
133 | [self setNeedsDisplay:YES];
134 | }
135 |
136 | @end
137 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMTabBar.h:
--------------------------------------------------------------------------------
1 | //
2 | // SMTabBar.h
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 30.01.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SMBar.h"
11 |
12 |
13 | @class SMTabBarItem;
14 | @protocol SMTabBarDelegate;
15 |
16 | @interface SMTabBar : SMBar
17 |
18 | @property (nonatomic, copy) NSArray *items;
19 | @property (nonatomic, weak) SMTabBarItem *selectedItem;
20 | @property (nonatomic, weak) IBOutlet id delegate;
21 |
22 | @end
23 |
24 |
25 | @protocol SMTabBarDelegate
26 |
27 | @optional
28 | - (BOOL)tabBar:(SMTabBar *)tabBar shouldSelectItem:(SMTabBarItem *)item;
29 | - (void)tabBar:(SMTabBar *)tabBar willSelectItem:(SMTabBarItem *)item;
30 | - (void)tabBar:(SMTabBar *)tabBar didSelectItem:(SMTabBarItem *)item;
31 |
32 | @end
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMTabBar.m:
--------------------------------------------------------------------------------
1 | //
2 | // SMTabBar.m
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 30.01.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import "SMTabBar.h"
10 | #import "SMTabBarItem.h"
11 | #import "SMTabBarButtonCell.h"
12 | #import "NSDictionary+SMKeyValueObserving.h"
13 |
14 |
15 | #define SMTabBarButtonWidth 32.0f
16 |
17 | @interface SMTabBar ()
18 |
19 | @property (nonatomic, copy) NSArray *barButtons;
20 |
21 | - (void)adjustSubviews;
22 |
23 | @end
24 |
25 | @implementation SMTabBar
26 |
27 | static char SMObservationContext;
28 |
29 | #pragma mark - Initialization / Deallocation
30 |
31 | - (id)initWithFrame:(NSRect)frame {
32 | self = [super initWithFrame:frame];
33 | if (self) {
34 | // Initialization code
35 |
36 | // add observer for properties
37 | [self addObserver:self forKeyPath:@"items" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:&SMObservationContext];
38 | [self addObserver:self forKeyPath:@"selectedItem" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:&SMObservationContext];
39 | }
40 | return self;
41 | }
42 |
43 | - (void)dealloc {
44 | // remove observer for properties
45 | [self removeObserver:self forKeyPath:@"items" context:&SMObservationContext];
46 | [self removeObserver:self forKeyPath:@"selectedItem" context:&SMObservationContext];
47 |
48 | // unbind button
49 | for (NSButton *button in self.barButtons) {
50 | [button unbind:@"image"];
51 | [button unbind:@"enabled"];
52 | [button unbind:@"toolTip"];
53 | [button unbind:@"keyEquivalent"];
54 | [button unbind:@"keyEquivalentModifierMask"];
55 | }
56 | }
57 |
58 | #pragma mark - Actions
59 |
60 | - (void)selectBarButton:(id)sender {
61 | // select a bar button
62 |
63 | NSUInteger itemIndex = [sender tag];
64 | SMTabBarItem *tabBarItem = [self.items objectAtIndex:itemIndex];
65 | if ([self.delegate respondsToSelector:@selector(tabBar:shouldSelectItem:)]) {
66 | BOOL shouldSelectItem = [self.delegate tabBar:self shouldSelectItem:tabBarItem];
67 | if (!shouldSelectItem) {
68 | return;
69 | }
70 | }
71 | if ([self.delegate respondsToSelector:@selector(tabBar:willSelectItem:)]) {
72 | [self.delegate tabBar:self willSelectItem:tabBarItem];
73 | }
74 | self.selectedItem = tabBarItem;
75 | if ([self.delegate respondsToSelector:@selector(tabBar:didSelectItem:)]) {
76 | [self.delegate tabBar:self didSelectItem:tabBarItem];
77 | }
78 | }
79 |
80 | #pragma mark - Private methods
81 |
82 | - (void)updateButtons {
83 | // remove old buttons
84 | for (NSButton *button in self.barButtons) {
85 | [button removeFromSuperview];
86 |
87 | [button unbind:@"image"];
88 | [button unbind:@"enabled"];
89 | [button unbind:@"toolTip"];
90 | [button unbind:@"keyEquivalent"];
91 | [button unbind:@"keyEquivalentModifierMask"];
92 | }
93 | self.barButtons = nil;
94 |
95 | // add new buttons
96 | NSMutableArray *newBarButtons = [NSMutableArray arrayWithCapacity:[self.items count]];
97 | NSUInteger selectedItemIndex = [self.items indexOfObject:self.selectedItem];
98 | NSUInteger itemIndex = 0;
99 | for (SMTabBarItem *item in self.items) {
100 | NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, SMTabBarButtonWidth, NSHeight(self.bounds))];
101 |
102 | // add special button cell for the selected state
103 | button.cell = [[SMTabBarButtonCell alloc] init];
104 |
105 | // set properties of the button
106 | button.image = item.image;
107 | [button setEnabled:item.enabled];
108 | button.state = itemIndex == selectedItemIndex ? NSOnState : NSOffState;
109 | button.tag = itemIndex;
110 | button.action = @selector(selectBarButton:);
111 | button.target = self;
112 | [button sendActionOn:NSLeftMouseDownMask];
113 | [self addSubview:button];
114 |
115 | // bind button properties to the item properties
116 | [button bind:@"image" toObject:item withKeyPath:@"image" options:nil];
117 | [button bind:@"enabled" toObject:item withKeyPath:@"enabled" options:nil];
118 | [button bind:@"toolTip" toObject:item withKeyPath:@"toolTip" options:nil];
119 | [button bind:@"keyEquivalent" toObject:item withKeyPath:@"keyEquivalent" options:nil];
120 | [button bind:@"keyEquivalentModifierMask" toObject:item withKeyPath:@"keyEquivalentModifierMask" options:nil];
121 |
122 | [newBarButtons addObject:button];
123 |
124 | itemIndex++;
125 | }
126 | self.barButtons = newBarButtons;
127 |
128 | // re-layout buttons
129 | [self adjustSubviews];
130 |
131 | // pre-select first button
132 | if (![self.items containsObject:self.selectedItem]) {
133 | self.selectedItem = [self.items count] > 0 ? [self.items objectAtIndex:0] : nil;
134 | }
135 | }
136 |
137 | - (void)updateButtonState {
138 | // update button states if the corresponding item is selected
139 | NSUInteger selectedItemIndex = [self.items indexOfObject:self.selectedItem];
140 | NSUInteger buttonIndex = 0;
141 | for (NSButton *button in self.barButtons) {
142 | button.state = buttonIndex == selectedItemIndex ? NSOnState : NSOffState;
143 | buttonIndex++;
144 | }
145 | }
146 |
147 | #pragma mark - Layout subviews
148 |
149 | - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
150 | [super resizeSubviewsWithOldSize:oldBoundsSize];
151 | [self adjustSubviews];
152 | }
153 |
154 | - (void)adjustSubviews {
155 | // layout subviews
156 | NSUInteger numberOfButtons = [self.barButtons count];
157 | CGFloat completeWidth = numberOfButtons * SMTabBarButtonWidth;
158 | CGFloat offset = floorf((NSWidth(self.bounds) - completeWidth) / 2.0f);
159 | for (NSButton *button in self.barButtons) {
160 | button.frame = NSMakeRect(offset, NSMinY(self.bounds), SMTabBarButtonWidth, NSHeight(self.bounds));
161 | offset += SMTabBarButtonWidth;
162 | }
163 | }
164 |
165 | #pragma mark - KVO
166 |
167 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
168 | if (context != &SMObservationContext) {
169 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
170 | return;
171 | }
172 |
173 | if (![change keyValueChanged]) {
174 | return;
175 | }
176 |
177 | if ([keyPath isEqualToString:@"items"]) {
178 | [self updateButtons];
179 | } else if ([keyPath isEqualToString:@"selectedItem"]) {
180 | [self updateButtonState];
181 | }
182 | }
183 |
184 | @end
185 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMTabBarButtonCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SMTabBarButtonCell.h
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 04.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SMTabBarButtonCell : NSButtonCell
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMTabBarButtonCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SMTabBarButtonCell.m
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 04.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import "SMTabBarButtonCell.h"
10 |
11 | @implementation SMTabBarButtonCell
12 |
13 | - (id)init {
14 | self = [super init];
15 | if (self) {
16 | self.bezelStyle = NSTexturedRoundedBezelStyle;
17 | }
18 | return self;
19 | }
20 |
21 | // prevent automatic state changes
22 | - (NSInteger)nextState {
23 | return self.state;
24 | }
25 |
26 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView {
27 |
28 | // Draw background only if the button is selected
29 | if (self.state == NSOnState) {
30 | [[NSGraphicsContext currentContext] saveGraphicsState];
31 |
32 | // light vertical gradient
33 | static NSGradient *gradient = nil;
34 | if (!gradient) {
35 | NSColor *color1 = [NSColor colorWithCalibratedWhite:0.7 alpha:0.0];
36 | NSColor *color2 = [NSColor colorWithCalibratedWhite:0.7 alpha:5.0];
37 | CGFloat loactions[] = {0.0f, 0.5f, 1.0f};
38 | gradient = [[NSGradient alloc] initWithColors:@[color1, color2, color1] atLocations:loactions colorSpace:[NSColorSpace genericGrayColorSpace]];
39 | }
40 | [gradient drawInRect:frame angle:-90.0f];
41 |
42 |
43 | // shadow on the left border
44 | NSShadow *shadow = [[NSShadow alloc] init];
45 | shadow.shadowOffset = NSMakeSize(1.0f, 0.0f);
46 | shadow.shadowBlurRadius = 2.0f;
47 | shadow.shadowColor = [NSColor darkGrayColor];
48 | [shadow set];
49 |
50 | // not visible color
51 | [[NSColor redColor] set];
52 |
53 | CGFloat radius = 50.0;
54 |
55 | NSPoint center = NSMakePoint(NSMinX(frame) - radius, NSMidY(frame));
56 | NSBezierPath *path = [NSBezierPath bezierPath];
57 | [path moveToPoint:center];
58 | [path appendBezierPathWithArcWithCenter:center
59 | radius:radius
60 | startAngle:-90.0f
61 | endAngle:90.0f];
62 | [path closePath];
63 | [path fill];
64 |
65 | // shadow of the right border
66 | shadow.shadowOffset = NSMakeSize(-1.0f, 0.0f);
67 | [shadow set];
68 |
69 | center = NSMakePoint(NSMaxX(frame) + radius, NSMidY(frame));
70 | path = [NSBezierPath bezierPath];
71 | [path moveToPoint:center];
72 | [path appendBezierPathWithArcWithCenter:center
73 | radius:radius
74 | startAngle:90.0f
75 | endAngle:270.0f];
76 | [path closePath];
77 | [path fill];
78 |
79 | [[NSGraphicsContext currentContext] restoreGraphicsState];
80 | }
81 | }
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMTabBarItem.h:
--------------------------------------------------------------------------------
1 | //
2 | // SMTabBarItem.h
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 03.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SMTabBarItem : NSObject
12 |
13 | @property (nonatomic) BOOL enabled;
14 | @property (nonatomic, strong) NSImage *image;
15 | @property (nonatomic, copy) NSString *toolTip;
16 | @property (nonatomic, copy) NSString *keyEquivalent;
17 | @property (nonatomic) NSUInteger keyEquivalentModifierMask;
18 | @property (nonatomic) NSInteger tag;
19 |
20 | - (id)initWithImage:(NSImage *)image tag:(NSInteger)tag;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/InspectorTabBar/SMTabBarItem.m:
--------------------------------------------------------------------------------
1 | //
2 | // SMTabBarItem.m
3 | // InspectorTabBar
4 | //
5 | // Created by Stephan Michels on 03.02.12.
6 | // Copyright (c) 2012 Stephan Michels Softwareentwicklung und Beratung. All rights reserved.
7 | //
8 |
9 | #import "SMTabBarItem.h"
10 |
11 | @implementation SMTabBarItem
12 |
13 | - (id)initWithImage:(NSImage *)image tag:(NSInteger)tag {
14 | self = [super init];
15 | if (self) {
16 | self.image = image;
17 | self.tag = tag;
18 | self.enabled = YES;
19 | }
20 | return self;
21 | }
22 |
23 | - (NSString *)description {
24 | return [NSString stringWithFormat:@"SMTabBarItem{tag=%li}", self.tag];
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/README.md:
--------------------------------------------------------------------------------
1 | source:
2 | https://github.com/smic/InspectorTabBar
3 |
--------------------------------------------------------------------------------
/third-party/SMTabBar/SMTabBar.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint SMTabBar.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 | s.name = "SMTabBar"
12 | s.version = "0.0.1"
13 | s.summary = "Tab bar like in the Xcode inspector."
14 | s.homepage = "https://github.com/smic/InspectorTabBar"
15 | s.license = { :type => "MIT" }
16 | s.author = { "smic" => "stephan.michels@gmail.com" }
17 | s.source = { :git => "git@github.com:smic/InspectorTabBar.git" }
18 | s.source_files = "InspectorTabBar/**/*.{h,m}"
19 | s.platform = :osx, "10.10"
20 | # s.public_header_files = "Classes/**/*.h"
21 | # s.requires_arc = true
22 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
23 | # s.dependency "JSONKit", "~> 1.4"
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/third-party/SPMediaKeyTap/README.md:
--------------------------------------------------------------------------------
1 | source:
2 | https://github.com/nevyn/SPMediaKeyTap
3 |
--------------------------------------------------------------------------------
/third-party/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface SPInvocationGrabber : NSObject {
4 | id _object;
5 | NSInvocation *_invocation;
6 | int frameCount;
7 | char **frameStrings;
8 | BOOL backgroundAfterForward;
9 | BOOL onMainAfterForward;
10 | BOOL waitUntilDone;
11 | }
12 | -(id)initWithObject:(id)obj;
13 | -(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
14 | @property (readonly, retain, nonatomic) id object;
15 | @property (readonly, retain, nonatomic) NSInvocation *invocation;
16 | @property BOOL backgroundAfterForward;
17 | @property BOOL onMainAfterForward;
18 | @property BOOL waitUntilDone;
19 | -(void)invoke; // will release object and invocation
20 | -(void)printBacktrace;
21 | -(void)saveBacktrace;
22 | @end
23 |
24 | @interface NSObject (SPInvocationGrabbing)
25 | -(id)grab;
26 | -(id)invokeAfter:(NSTimeInterval)delta;
27 | -(id)nextRunloop;
28 | -(id)inBackground;
29 | -(id)onMainAsync:(BOOL)async;
30 | @end
31 |
--------------------------------------------------------------------------------
/third-party/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m:
--------------------------------------------------------------------------------
1 | #import "NSObject+SPInvocationGrabbing.h"
2 | #import
3 |
4 | #pragma mark Invocation grabbing
5 | @interface SPInvocationGrabber ()
6 | @property (readwrite, retain, nonatomic) id object;
7 | @property (readwrite, retain, nonatomic) NSInvocation *invocation;
8 |
9 | @end
10 |
11 | @implementation SPInvocationGrabber
12 | - (id)initWithObject:(id)obj;
13 | {
14 | return [self initWithObject:obj stacktraceSaving:YES];
15 | }
16 |
17 | -(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
18 | {
19 | self.object = obj;
20 |
21 | if(saveStack)
22 | [self saveBacktrace];
23 |
24 | return self;
25 | }
26 | -(void)dealloc;
27 | {
28 | free(frameStrings);
29 | self.object = nil;
30 | self.invocation = nil;
31 | [super dealloc];
32 | }
33 | @synthesize invocation = _invocation, object = _object;
34 |
35 | @synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone;
36 | - (void)runInBackground;
37 | {
38 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
39 | @try {
40 | [self invoke];
41 | }
42 | @finally {
43 | [pool drain];
44 | }
45 | }
46 |
47 |
48 | - (void)forwardInvocation:(NSInvocation *)anInvocation {
49 | [anInvocation retainArguments];
50 | anInvocation.target = _object;
51 | self.invocation = anInvocation;
52 |
53 | if(backgroundAfterForward)
54 | [NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil];
55 | else if(onMainAfterForward)
56 | [self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone];
57 | }
58 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector {
59 | NSMethodSignature *signature = [super methodSignatureForSelector:inSelector];
60 | if (signature == NULL)
61 | signature = [_object methodSignatureForSelector:inSelector];
62 |
63 | return signature;
64 | }
65 |
66 | - (void)invoke;
67 | {
68 |
69 | @try {
70 | [_invocation invoke];
71 | }
72 | @catch (NSException * e) {
73 | NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e);
74 | [self printBacktrace];
75 | printf("\n");
76 | [e raise];
77 | }
78 |
79 | self.invocation = nil;
80 | self.object = nil;
81 | }
82 |
83 | -(void)saveBacktrace;
84 | {
85 | void *backtraceFrames[128];
86 | frameCount = backtrace(&backtraceFrames[0], 128);
87 | frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount);
88 | }
89 | -(void)printBacktrace;
90 | {
91 | for(int x = 3; x < frameCount; x++) {
92 | if(frameStrings[x] == NULL) { break; }
93 | printf("%s\n", frameStrings[x]);
94 | }
95 | }
96 | @end
97 |
98 | @implementation NSObject (SPInvocationGrabbing)
99 | -(id)grab;
100 | {
101 | return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease];
102 | }
103 | -(id)invokeAfter:(NSTimeInterval)delta;
104 | {
105 | id grabber = [self grab];
106 | [NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO];
107 | return grabber;
108 | }
109 | - (id)nextRunloop;
110 | {
111 | return [self invokeAfter:0];
112 | }
113 | -(id)inBackground;
114 | {
115 | SPInvocationGrabber *grabber = [self grab];
116 | grabber.backgroundAfterForward = YES;
117 | return grabber;
118 | }
119 | -(id)onMainAsync:(BOOL)async;
120 | {
121 | SPInvocationGrabber *grabber = [self grab];
122 | grabber.onMainAfterForward = YES;
123 | grabber.waitUntilDone = !async;
124 | return grabber;
125 | }
126 |
127 | @end
128 |
--------------------------------------------------------------------------------
/third-party/SPMediaKeyTap/SPMediaKeyTap.h:
--------------------------------------------------------------------------------
1 | #include
2 | #import
3 | #import
4 |
5 | // http://overooped.com/post/2593597587/mediakeys
6 |
7 | #define SPSystemDefinedEventMediaKeys 8
8 |
9 | @interface SPMediaKeyTap : NSObject {
10 | EventHandlerRef _app_switching_ref;
11 | EventHandlerRef _app_terminating_ref;
12 | CFMachPortRef _eventPort;
13 | CFRunLoopSourceRef _eventPortSource;
14 | CFRunLoopRef _tapThreadRL;
15 | BOOL _shouldInterceptMediaKeyEvents;
16 | id _delegate;
17 | // The app that is frontmost in this list owns media keys
18 | NSMutableArray *_mediaKeyAppList;
19 | }
20 | + (NSArray*)defaultMediaKeyUserBundleIdentifiers;
21 |
22 | -(id)initWithDelegate:(id)delegate;
23 |
24 | +(BOOL)usesGlobalMediaKeyTap;
25 | -(void)startWatchingMediaKeys;
26 | -(void)stopWatchingMediaKeys;
27 | -(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event;
28 | @end
29 |
30 | @interface NSObject (SPMediaKeyTapDelegate)
31 | -(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
32 | @end
33 |
34 | #ifdef __cplusplus
35 | extern "C" {
36 | #endif
37 |
38 | extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey;
39 | extern NSString *kIgnoreMediaKeysDefaultsKey;
40 |
41 | #ifdef __cplusplus
42 | }
43 | #endif
--------------------------------------------------------------------------------
/third-party/SPMediaKeyTap/SPMediaKeyTap.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint SPMediaKeyTap.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 | s.name = "SPMediaKeyTap"
12 | s.version = "0.0.1"
13 | s.summary = "SPMediaKeyTap is a global event tap for the play/pause, prev and next keys on the keyboard."
14 | s.homepage = "https://github.com/nevyn/SPMediaKeyTap"
15 | s.license = { :type => "BSD 3-Clause"}
16 | s.author = { "nevyn" => "nevyn.jpg@gmail.com" }
17 | s.platform = :osx
18 | # s.osx.deployment_target = "10.7"
19 | s.source = { :git => "git://github.com/sonoramac/SPMediaKeyTap.git" }
20 | s.source_files = 'SPMediaKeyTap.{h,m}', 'SPInvocationGrabbing/NSObject+SPInvocationGrabbing.{h,m}'
21 | # s.public_header_files = "Classes/**/*.h"
22 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
23 | # s.frameworks = "SomeFramework", "AnotherFramework"
24 | # s.library = "iconv"
25 | # s.libraries = "iconv", "xml2"
26 | s.requires_arc = false
27 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
28 | # s.dependency "JSONKit", "~> 1.4"
29 |
30 | end
31 |
--------------------------------------------------------------------------------