├── .gitignore
├── .idea
├── .name
├── GIFs.iml
├── codeStyleSettings.xml
├── dictionaries
│ └── orta.xml
├── encodings.xml
├── misc.xml
├── modules.xml
├── scopes
│ └── scope_settings.xml
├── vcs.xml
├── workspace.xml
└── xcode.xml
├── LICENSE
├── README.md
├── design
├── Icon.png
├── Icon.sketch
│ ├── Data
│ ├── QuickLook
│ │ ├── Preview.png
│ │ └── Thumbnail.png
│ ├── metadata
│ └── version
└── Icon@2x.png
├── objc
├── .idea
│ ├── .name
│ ├── dictionaries
│ │ └── orta.xml
│ ├── encodings.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── objc.iml
│ ├── scopes
│ │ └── scope_settings.xml
│ ├── vcs.xml
│ ├── workspace.xml
│ └── xcode.xml
├── GIFs.xcodeproj
│ ├── GIFs.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ └── GIFs.xccheckout
│ │ └── xcuserdata
│ │ │ └── orta.xcuserdatad
│ │ │ └── xcschemes
│ │ │ ├── GIFs.xcscheme
│ │ │ └── xcschememanagement.plist
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata
│ │ │ └── GIFs.xccheckout
│ │ └── xcuserdata
│ │ │ └── orta.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ ├── fabio.xcuserdatad
│ │ └── xcschemes
│ │ │ ├── All The GIFs.xcscheme
│ │ │ ├── Install.xcscheme
│ │ │ └── xcschememanagement.plist
│ │ └── orta.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints.xcbkptlist
│ │ └── xcschemes
│ │ ├── GIFs.xcscheme
│ │ ├── Install.xcscheme
│ │ └── xcschememanagement.plist
├── GIFs.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── GIFs.xccheckout
├── GIFs
│ ├── AboutController.swift
│ ├── DotSlash.png
│ ├── GIFs-Bridging-Header.h
│ ├── GIFs-Icon.icns
│ ├── GIFs-Info.plist
│ ├── GIFs-Prefix.pch
│ ├── GIFs.entitlements
│ ├── Giphy_API_Logo_ForWhite_Trans.gif
│ ├── Github.png
│ ├── NSString+StringBetweenStrings.h
│ ├── NSString+StringBetweenStrings.m
│ ├── ORAppDelegate.h
│ ├── ORAppDelegate.m
│ ├── ORDarkBlueView.h
│ ├── ORDarkBlueView.m
│ ├── ORGIFActionsController.h
│ ├── ORGIFActionsController.m
│ ├── ORGIFController.h
│ ├── ORGIFController.m
│ ├── ORGIFRightClickMenuMaker.h
│ ├── ORGIFRightClickMenuMaker.m
│ ├── ORImageBrowserView.h
│ ├── ORImageBrowserView.m
│ ├── ORImageView.h
│ ├── ORImageView.m
│ ├── ORMenuController.h
│ ├── ORMenuController.m
│ ├── ORMiddleGreyView.h
│ ├── ORMiddleGreyView.m
│ ├── ORSearchTextField.h
│ ├── ORSearchTextField.m
│ ├── ORSimpleSourceListView.h
│ ├── ORSimpleSourceListView.m
│ ├── ORSourcesController.h
│ ├── ORSourcesController.m
│ ├── ORStarredSourceController.h
│ ├── ORStarredSourceController.m
│ ├── ORTintedVisualEffectView.swift
│ ├── ORTumblrController.h
│ ├── ORTumblrController.m
│ ├── ORWebViewDelegateStuff.h
│ ├── ORWebViewDelegateStuff.m
│ ├── ORWindowDraggableVisualEffectsView.h
│ ├── ORWindowDraggableVisualEffectsView.m
│ ├── ORWindowTitleDecorationController.swift
│ ├── Reddit.png
│ ├── Reddit@2x.png
│ ├── RedditWhite.png
│ ├── RedditWhite@2x.png
│ ├── SBSystemPreferences.h
│ ├── Search.png
│ ├── Search@2x.png
│ ├── SearchWhite.png
│ ├── SearchWhite@2x.png
│ ├── ShadowView.swift
│ ├── TwitterBird.png
│ ├── about0.jpg
│ ├── about1.jpg
│ ├── about10.jpg
│ ├── about11.jpg
│ ├── about12.jpg
│ ├── about13.jpg
│ ├── about14.jpg
│ ├── about2.jpg
│ ├── about3.jpg
│ ├── about4.jpg
│ ├── about5.jpg
│ ├── about6.jpg
│ ├── about7.jpg
│ ├── about8.jpg
│ ├── about9.jpg
│ ├── close.png
│ ├── close@2x.png
│ ├── close_active.png
│ ├── close_active@2x.png
│ ├── en.lproj
│ │ ├── Credits.rtf
│ │ ├── InfoPlist.strings
│ │ └── MainMenu.xib
│ ├── gif_template.html
│ ├── main.m
│ ├── more.png
│ ├── plus_active.png
│ ├── plus_active@2x.png
│ ├── plus_active@2x.pxm
│ ├── shadow.png
│ ├── tick.png
│ ├── tick@2x.png
│ ├── tick_active.png
│ ├── tick_active@2x.png
│ ├── tumblr_t.png
│ ├── tumblr_t@2x.png
│ ├── tumblr_t_active.png
│ └── tumblr_t_active@2x.png
├── Gemfile
├── Gemfile.lock
├── Makefile
├── Podfile
└── Podfile.lock
└── web
├── GIFs.app.zip
└── yosemite.png
/.gitignore:
--------------------------------------------------------------------------------
1 | objc/pods
2 | xcuserdata
3 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | GIFs
--------------------------------------------------------------------------------
/.idea/GIFs.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/.idea/dictionaries/orta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | Classes
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 | false
344 |
345 |
346 |
347 |
348 | 1358688222820
349 | 1358688222820
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
--------------------------------------------------------------------------------
/.idea/xcode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, orta therox
2 | All rights reserved.
3 |
4 | This is a customized BSD license, you don't have to write that you've
5 | used my code in your released apps. Also by using this code you agree
6 | to not wholesale copy my app; I love competition, but I'd rather compete
7 | on user experience. Thanks.
8 |
9 | Redistribution and use in source and binary forms, with or without
10 | modification, are permitted provided that the following conditions are met:
11 |
12 | 1. Redistributions of source code must retain the above copyright notice, this
13 | list of conditions and the following disclaimer.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
26 | The views and conclusions contained in the software and documentation are those
27 | of the authors and should not be interpreted as representing official policies,
28 | either expressed or implied, of the FreeBSD Project.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 2012's word of the year: GIF.
2 | --------
3 |
4 | See https://github.com/manmal/GIFs for an updated build
5 |
6 | 
7 |
8 | ### Download
9 |
10 | You can grab the app from [Mac App Store](https://itunes.apple.com/us/app/gifs/id961850017?l=en&mt=12) (it's free! 🎉) or download the latest version directly [here](https://raw.github.com/orta/GIFs/master/web/GIFs.app.zip).
11 |
12 | ### Compiling
13 |
14 | ```
15 | git clone https://github.com/orta/GIFs.git
16 | cd GIFs/objc
17 | make bootstrap
18 | ```
19 |
--------------------------------------------------------------------------------
/design/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/design/Icon.png
--------------------------------------------------------------------------------
/design/Icon.sketch/Data:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/design/Icon.sketch/Data
--------------------------------------------------------------------------------
/design/Icon.sketch/QuickLook/Preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/design/Icon.sketch/QuickLook/Preview.png
--------------------------------------------------------------------------------
/design/Icon.sketch/QuickLook/Thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/design/Icon.sketch/QuickLook/Thumbnail.png
--------------------------------------------------------------------------------
/design/Icon.sketch/metadata:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | app
6 | com.bohemiancoding.sketch
7 | build
8 | 5355
9 | commit
10 | b7d299b0a34651d1a0e066786b75aa36168d5809
11 | fonts
12 |
13 | AvenirNext-Bold
14 |
15 | length
16 | 11705
17 | version
18 | 18
19 |
20 |
21 |
--------------------------------------------------------------------------------
/design/Icon.sketch/version:
--------------------------------------------------------------------------------
1 | 18
--------------------------------------------------------------------------------
/design/Icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/design/Icon@2x.png
--------------------------------------------------------------------------------
/objc/.idea/.name:
--------------------------------------------------------------------------------
1 | All The GIFs
--------------------------------------------------------------------------------
/objc/.idea/dictionaries/orta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/objc/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/objc/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | C/C++
12 |
13 |
14 | CSS
15 |
16 |
17 | Code style issuesJavaScript
18 |
19 |
20 | Data flow analysisC/C++
21 |
22 |
23 | JavaScript
24 |
25 |
26 |
27 |
28 | C/C++
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | false
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/objc/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/objc/.idea/objc.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/objc/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/objc/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/objc/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 | 1406889306032
186 | 1406889306032
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 | file://$PROJECT_DIR$/../../GIFKit/Pod/Classes/GIF+RedditDictionary.m
226 | 57
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
--------------------------------------------------------------------------------
/objc/.idea/xcode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/GIFs.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/GIFs.xcodeproj/project.xcworkspace/xcshareddata/GIFs.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 18C57799-D27F-48EA-A71E-4FA79879A9D6
9 | IDESourceControlProjectName
10 | GIFs
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 9D352ECE-BDB8-47FB-ACC6-8421F7FCFF26
14 | https://github.com/orta/GIFs.git
15 |
16 | IDESourceControlProjectPath
17 | objc/GIFs.xcodeproj/project.xcworkspace
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 9D352ECE-BDB8-47FB-ACC6-8421F7FCFF26
21 | ../../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/orta/GIFs.git
25 | IDESourceControlProjectVersion
26 | 110
27 | IDESourceControlProjectWCCIdentifier
28 | 9D352ECE-BDB8-47FB-ACC6-8421F7FCFF26
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 9D352ECE-BDB8-47FB-ACC6-8421F7FCFF26
36 | IDESourceControlWCCName
37 | GIFs
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/GIFs.xcodeproj/xcuserdata/orta.xcuserdatad/xcschemes/GIFs.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/GIFs.xcodeproj/xcuserdata/orta.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | GIFs.xcscheme
8 |
9 | orderHint
10 | 3
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 60ECD1AE16A1FA6400A0FB7A
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/project.xcworkspace/xcshareddata/GIFs.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | DFBD1451-D7EB-40D8-AB51-9C6553F48E07
9 | IDESourceControlProjectName
10 | GIFs
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
14 | https://github.com/orta/GIFs.git
15 |
16 | IDESourceControlProjectPath
17 | objc/GIFs.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
21 | ../../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/orta/GIFs.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
36 | IDESourceControlWCCName
37 | GIFs
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/project.xcworkspace/xcuserdata/orta.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs.xcodeproj/project.xcworkspace/xcuserdata/orta.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/xcuserdata/fabio.xcuserdatad/xcschemes/All The GIFs.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/xcuserdata/fabio.xcuserdatad/xcschemes/Install.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/xcuserdata/fabio.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | All The GIFs.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 | Install.xcscheme
13 |
14 | orderHint
15 | 6
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | 60ECD1AE16A1FA6400A0FB7A
21 |
22 | primary
23 |
24 |
25 | E59DFC3518EB20980014EDA0
26 |
27 | primary
28 |
29 |
30 | E59DFC3918EB20C90014EDA0
31 |
32 | primary
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/xcuserdata/orta.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/xcuserdata/orta.xcuserdatad/xcschemes/GIFs.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
65 |
67 |
73 |
74 |
75 |
76 |
77 |
78 |
84 |
86 |
92 |
93 |
94 |
95 |
97 |
98 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/xcuserdata/orta.xcuserdatad/xcschemes/Install.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/objc/GIFs.xcodeproj/xcuserdata/orta.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | GIFs.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 | Install.xcscheme
13 |
14 | orderHint
15 | 1
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | 60ECD1AE16A1FA6400A0FB7A
21 |
22 | primary
23 |
24 |
25 | E59DFC3918EB20C90014EDA0
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/objc/GIFs.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/objc/GIFs.xcworkspace/xcshareddata/GIFs.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 41CA408B-1D1F-492F-856B-C84128DAD663
9 | IDESourceControlProjectName
10 | GIFs
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
14 | https://github.com/orta/GIFs.git
15 |
16 | IDESourceControlProjectPath
17 | objc/GIFs.xcworkspace
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/orta/GIFs.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 0C026FFCE33D1340AF39A8387EB741DBFB2E627F
36 | IDESourceControlWCCName
37 | GIFs
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/objc/GIFs/AboutController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AboutController.swift
3 | // GIFs
4 | //
5 | // Created by Orta on 8/31/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import AppKit
11 |
12 | class AboutController : NSObject {
13 |
14 | @IBOutlet weak var subtitleField: NSTextField!
15 | @IBOutlet weak var aboutWindow: NSWindow!
16 | @IBOutlet weak var mainWindow: NSWindow!
17 | @IBOutlet weak var backgroundImageView: NSImageView!
18 |
19 | @IBOutlet weak var titleBackgroundView: NSView!
20 |
21 | override func awakeFromNib() {
22 | titleBackgroundView.layer!.backgroundColor = NSColor(calibratedWhite: 0, alpha: 0.3).CGColor
23 | }
24 |
25 | @IBAction func openModal(sender: AnyObject) {
26 |
27 | let rando:UInt32 = arc4random_uniform(13)
28 | backgroundImageView.image = NSImage(named: "about\(rando)")
29 |
30 | mainWindow.beginSheet(aboutWindow, completionHandler:nil)
31 | }
32 |
33 |
34 | @IBAction func closeModal(sender: AnyObject) {
35 | mainWindow.endSheet(aboutWindow)
36 | }
37 |
38 | @IBAction func openGithub(sender: AnyObject) {
39 | let workspace = NSWorkspace.sharedWorkspace()
40 | workspace.openURL(NSURL(string: "http://github.com/orta")!);
41 | }
42 |
43 | @IBAction func openTwitter(sender: AnyObject) {
44 | let workspace = NSWorkspace.sharedWorkspace()
45 | if let tweetbot = workspace.fullPathForApplication("Tweetbot") {
46 | workspace.openURL(NSURL(string: "tweetbot:///user_profile/orta")!);
47 |
48 | } else {
49 | workspace.openURL(NSURL(string: "http://twitter.com/orta")!);
50 | }
51 |
52 | }
53 |
54 | @IBAction func openMySite(sender: AnyObject) {
55 | let workspace = NSWorkspace.sharedWorkspace()
56 | workspace.openURL(NSURL(string: "http://orta.io")!);
57 |
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/objc/GIFs/DotSlash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/DotSlash.png
--------------------------------------------------------------------------------
/objc/GIFs/GIFs-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import
6 | #import
--------------------------------------------------------------------------------
/objc/GIFs/GIFs-Icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/GIFs-Icon.icns
--------------------------------------------------------------------------------
/objc/GIFs/GIFs-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 | GIFs-Icon
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleTypeRole
27 | Editor
28 | CFBundleURLSchemes
29 |
30 | gifs-app
31 |
32 |
33 |
34 | CFBundleVersion
35 | 1.1.0
36 | LSApplicationCategoryType
37 | public.app-category.entertainment
38 | LSMinimumSystemVersion
39 | ${MACOSX_DEPLOYMENT_TARGET}
40 | NSAppTransportSecurity
41 |
42 | NSAllowsArbitraryLoads
43 |
44 |
45 | NSHumanReadableCopyright
46 | Copyright © 2014 Orta Therox. All rights reserved.
47 | NSMainNibFile
48 | MainMenu
49 | NSPrincipalClass
50 | NSApplication
51 |
52 |
53 |
--------------------------------------------------------------------------------
/objc/GIFs/GIFs-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'GIFs' target in the 'GIFs' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #import
7 | #import
8 | #endif
9 |
--------------------------------------------------------------------------------
/objc/GIFs/GIFs.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-write
8 |
9 | com.apple.security.network.client
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/objc/GIFs/Giphy_API_Logo_ForWhite_Trans.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/Giphy_API_Logo_ForWhite_Trans.gif
--------------------------------------------------------------------------------
/objc/GIFs/Github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/Github.png
--------------------------------------------------------------------------------
/objc/GIFs/NSString+StringBetweenStrings.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+StringBetweenStrings.h
3 | // Artsy Folio
4 | //
5 | // Created by orta therox on 03/10/2012.
6 | // Copyright (c) 2012 http://art.sy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSString (StringBetweenStrings)
12 |
13 | // on a string "hello world" with arguments "e" and "d"
14 | // will return "llo world" or nil if it can't find the start or end.
15 |
16 | - (NSString *)substringBetween:(NSString *)start and:(NSString *)end;
17 | @end
18 |
--------------------------------------------------------------------------------
/objc/GIFs/NSString+StringBetweenStrings.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+StringBetweenStrings.m
3 | // Artsy Folio
4 | //
5 | // Created by orta therox on 03/10/2012.
6 | // Copyright (c) 2012 http://art.sy. All rights reserved.
7 | //
8 |
9 | #import "NSString+StringBetweenStrings.h"
10 |
11 | @implementation NSString (StringBetweenStrings)
12 |
13 | - (NSString *)substringBetween:(NSString *)start and:(NSString *)end {
14 | NSRange startingRange = [self rangeOfString:start];
15 | NSRange endingRange = [self rangeOfString:end];
16 |
17 | if (startingRange.location == NSNotFound || endingRange.location == NSNotFound) {
18 | return nil;
19 | }
20 |
21 | NSInteger length = endingRange.location - startingRange.location - startingRange.length;
22 | if (length < 0) {
23 | NSLog(@"length is below zero, you need a more specific end result");
24 | return nil;
25 | }
26 |
27 | NSInteger location = startingRange.location + startingRange.length;
28 |
29 | if (length + location > self.length || location < 0) {
30 | return nil;
31 | }
32 |
33 | return [self substringWithRange:NSMakeRange(location, length)];
34 | }
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/objc/GIFs/ORAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORAppDelegate.h
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class ORMenuController;
12 | @interface ORAppDelegate : NSObject
13 |
14 | @property (weak) IBOutlet NSProgressIndicator *networkProgress;
15 | @property (assign) IBOutlet NSWindow *window;
16 | @property (strong) IBOutlet ORMenuController *menuController;
17 |
18 | + (void)setNetworkActivity:(BOOL)activity;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/objc/GIFs/ORAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORAppDelegate.m
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORAppDelegate.h"
10 | #import "ORMenuController.h"
11 |
12 | @implementation ORAppDelegate
13 |
14 | static ORAppDelegate *_sharedInstance = nil;
15 |
16 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
17 | _sharedInstance = self;
18 |
19 | self.window.appearance = [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight];
20 | self.window.titleVisibility = NSWindowTitleHidden;
21 | self.window.titlebarAppearsTransparent = YES;
22 | self.window.movableByWindowBackground = YES;
23 |
24 | // They get cropped
25 | // [self moveTitleBarButtons];
26 |
27 | [self.menuController.menuTableView reloadData];
28 | [self.menuController.menuTableView selectDefaultItem];
29 | }
30 |
31 | - (void)moveTitlebarButtons
32 | {
33 |
34 | NSButton *closeButton = [self.window standardWindowButton:NSWindowCloseButton];
35 | NSButton *zoomButton = [self.window standardWindowButton:NSWindowZoomButton];
36 | NSButton *minimizeButton = [self.window standardWindowButton:NSWindowMiniaturizeButton];
37 |
38 | closeButton.frame = NSMakeRect(closeButton.frame.origin.x+5,
39 | closeButton.frame.origin.y-12,
40 | closeButton.frame.size.height,
41 | closeButton.frame.size.width);
42 |
43 | zoomButton.frame = NSMakeRect(zoomButton.frame.origin.x+5,
44 | zoomButton.frame.origin.y-12,
45 | zoomButton.frame.size.height,
46 | zoomButton.frame.size.width);
47 |
48 | minimizeButton.frame = NSMakeRect(minimizeButton.frame.origin.x+5,
49 | minimizeButton.frame.origin.y-12,
50 | minimizeButton.frame.size.height,
51 | minimizeButton.frame.size.width);
52 | }
53 |
54 | - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
55 | return YES;
56 | }
57 |
58 | + (void)setNetworkActivity:(BOOL)activity
59 | {
60 | if (activity) {
61 | [_sharedInstance.networkProgress startAnimation:self];
62 | } else {
63 | [_sharedInstance.networkProgress stopAnimation:self];
64 | }
65 | }
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/objc/GIFs/ORDarkBlueView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORDarkBlueView.h
3 | // GIFs
4 | //
5 | // Created by Orta on 14/11/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ORDarkBlueView : NSView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/objc/GIFs/ORDarkBlueView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORDarkBlueView.m
3 | // GIFs
4 | //
5 | // Created by Orta on 14/11/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORDarkBlueView.h"
10 |
11 | @implementation ORDarkBlueView
12 |
13 | - (void)drawRect:(NSRect)dirtyRect {
14 | [[NSColor colorWithCalibratedRed:0.150 green:0.140 blue:0.169 alpha:1.000] setFill];
15 | NSRectFill(dirtyRect);
16 | [super drawRect:dirtyRect];
17 | }
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/objc/GIFs/ORGIFActionsController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORGIFActionsController.h
3 | // GIFs
4 | //
5 | // Created by Bryan Luby on 5/25/15.
6 | // Copyright (c) 2015 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | * Helper class for shared contextual menu and keyboard shorcut actions on GIFs.
13 | */
14 | @interface ORGIFActionsController : NSObject
15 |
16 | + (void)tweetOutLinkToURL:(NSURL *)url;
17 |
18 | + (void)tweetOrtaLinkToURL:(NSURL *)url;
19 |
20 | + (void)copyGIFDownloadURLToClipboard:(NSURL *)downloadURL;
21 |
22 | + (void)copyGIFMarkdownToClipboardWithSourceTitle:(NSString *)sourceTitle downloadURL:(NSURL *)downloadURL;
23 |
24 | + (void)openGIFDownloadURLInBrowser:(NSURL *)downloadURL;
25 |
26 | + (void)openGIFContextURLInBrowser:(NSURL *)contextURL;
27 |
28 | + (void)downloadGIFWithURL:(NSURL *)downloadURL completion:(void(^)(BOOL success, NSError *error))completion;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/objc/GIFs/ORGIFActionsController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORGIFActionsController.m
3 | // GIFs
4 | //
5 | // Created by Bryan Luby on 5/25/15.
6 | // Copyright (c) 2015 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORGIFActionsController.h"
10 | #import
11 | #import
12 | #import
13 |
14 | @implementation ORGIFActionsController
15 |
16 | + (void)tweetOrtaLinkToURL:(NSURL *)url
17 | {
18 | NSString *tweet = [NSString stringWithFormat:@"@orta - %@", url.absoluteString];
19 | [self tweet:tweet];
20 | }
21 |
22 | + (void)tweetOutLinkToURL:(NSURL *)url
23 | {
24 | NSString *tweet = [NSString stringWithFormat:@"%@", url.absoluteString];
25 | [self tweet:tweet];
26 | }
27 |
28 | + (void)tweet:(NSString *)tweet
29 | {
30 | GifsKeys *keys = [[GifsKeys alloc] init];
31 | STTwitterAPI *twitter = [STTwitterAPI twitterAPIWithOAuthConsumerKey: [keys randoTwitterBotConsumerKey]
32 | consumerSecret: [keys randoTwitterBotConsumerSecret]
33 | oauthToken: [keys randoTwitterBotOAuthToken]
34 | oauthTokenSecret: [keys randoTwitterBotOAuthTokenSecret]];
35 |
36 | [twitter postStatusUpdate:tweet inReplyToStatusID:nil latitude:nil longitude:nil placeID:@"GIFS.app" displayCoordinates:nil trimUser:@0 successBlock:^(NSDictionary *status) {
37 |
38 | } errorBlock:^(NSError *error) {
39 |
40 | }];
41 | }
42 |
43 | + (void)copyGIFDownloadURLToClipboard:(NSURL *)downloadURL
44 | {
45 | [[NSPasteboard generalPasteboard] clearContents];
46 | [[NSPasteboard generalPasteboard] writeObjects:@[downloadURL.absoluteString]];
47 | }
48 |
49 | + (void)copyGIFMarkdownToClipboardWithSourceTitle:(NSString *)sourceTitle downloadURL:(NSURL *)downloadURL
50 | {
51 | [[NSPasteboard generalPasteboard] clearContents];
52 | NSString *markdown = [NSString stringWithFormat:@"", sourceTitle, downloadURL];
53 | [[NSPasteboard generalPasteboard] writeObjects:@[markdown]];
54 | }
55 |
56 | + (void)openGIFDownloadURLInBrowser:(NSURL *)downloadURL
57 | {
58 | [self openURL:downloadURL];
59 | }
60 |
61 | + (void)openGIFContextURLInBrowser:(NSURL *)contextURL
62 | {
63 | [self openURL:contextURL];
64 | }
65 |
66 | + (void)openURL:(NSURL *)URL
67 | {
68 | [[NSWorkspace sharedWorkspace] openURL:URL];
69 | }
70 |
71 | + (void)downloadGIFWithURL:(NSURL *)downloadURL completion:(void(^)(BOOL success, NSError *error))completion
72 | {
73 | NSSavePanel *savePanel = [NSSavePanel savePanel];
74 | savePanel.allowedFileTypes = @[@"gif"];
75 | savePanel.canCreateDirectories = YES;
76 | savePanel.allowsOtherFileTypes = NO;
77 | savePanel.canSelectHiddenExtension = YES;
78 |
79 | NSString *downloadDirectoryPath = [ NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSUserDomainMask, YES) firstObject];
80 | NSURL *downloadDirectoryURL = [NSURL fileURLWithPath:downloadDirectoryPath];
81 | static NSURL * lastUserSelectedDirectoryURL = nil;
82 | savePanel.directoryURL = lastUserSelectedDirectoryURL ? lastUserSelectedDirectoryURL : downloadDirectoryURL;
83 | savePanel.nameFieldStringValue = downloadURL.lastPathComponent;
84 |
85 | NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:downloadURL];
86 | AFHTTPRequestOperation *afhttpRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
87 | [afhttpRequestOperation
88 | setDownloadProgressBlock:^(NSUInteger bytesRead, long long int totalBytesRead, long long int totalBytesExpectedToRead) {
89 |
90 | }];
91 |
92 | [savePanel beginWithCompletionHandler:^(NSInteger result) {
93 | if (result) {
94 | lastUserSelectedDirectoryURL = savePanel.directoryURL;
95 |
96 | [afhttpRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, NSData *responseObject) {
97 | BOOL success = [responseObject writeToURL:savePanel.URL atomically:YES];
98 |
99 | NSError *error;
100 | if (!success) {
101 | NSString *errorString = NSLocalizedString(@"Failed to save file", @"Failed to save file");
102 | error = [NSError errorWithDomain:NSCocoaErrorDomain
103 | code:NSFileWriteUnknownError
104 | userInfo:@{NSLocalizedDescriptionKey: errorString}];
105 | NSLog(@"%@", errorString);
106 | } else {
107 | NSLog(@"Successfully downloaded file.");
108 | }
109 |
110 | if (completion) {
111 | completion(success, error);
112 | }
113 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
114 | NSLog(@"Fetch failed\n %@ \n %@", operation, error);
115 |
116 | if (completion) {
117 | completion(NO, error);
118 | }
119 | }];
120 |
121 | [afhttpRequestOperation start];
122 | }
123 | }];
124 | }
125 |
126 | @end
127 |
--------------------------------------------------------------------------------
/objc/GIFs/ORGIFController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORGIFController.h
3 | // GIFs
4 | //
5 | // Created by orta therox on 13/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "ORSimpleSourceListView.h"
12 | #import
13 | #import
14 | #import "ORImageBrowserView.h"
15 |
16 | @class GIF, ORSubredditNetworkModel, ORGiphyNetworkModel, ORTumblrController, ORStarredSourceController, ORMenuController;
17 |
18 | @interface ORGIFController : NSObject
19 |
20 | @property (weak) IBOutlet IKImageBrowserView *collectionView;
21 |
22 | @property (weak) IBOutlet WebView *webView;
23 | @property (weak) IBOutlet NSButton *openGIFContextButton;
24 |
25 | @property (weak) IBOutlet NSPopover *createSourcePopover;
26 |
27 | @property (weak) IBOutlet NSProgressIndicator *downloadProgressIndicator;
28 |
29 | @property (weak) IBOutlet ORSubredditNetworkModel *redditController;
30 | @property (weak) IBOutlet ORGiphyNetworkModel *searchController;
31 | @property (weak) IBOutlet ORTumblrController *tumblrController;
32 | @property (weak) IBOutlet ORStarredSourceController *starredController;
33 | @property (weak) IBOutlet ORMenuController *menuController;
34 |
35 | @property (weak) IBOutlet NSTextField *sectionTitle;
36 | @property (weak) IBOutlet NSTextField *gifTitle;
37 |
38 | @property (strong) GIF *currentGIF;
39 |
40 | - (void)gotNewGIFs;
41 |
42 | - (void)getGIFsFromSourceString:(NSString *)string;
43 |
44 | - (NSString *)gifFilePath;
45 |
46 | - (IBAction)openCurrentGIF:(NSButton *)sender;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/objc/GIFs/ORGIFController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORGIFController.m
3 | // GIFs
4 | //
5 | // Created by orta therox on 13/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORGIFController.h"
10 | #import
11 | #import
12 | #import
13 | #import "ORTumblrController.h"
14 | #import "ORStarredSourceController.h"
15 | #import
16 | #import "NSString+StringBetweenStrings.h"
17 | #import "ORMenuController.h"
18 | #import "GIFs-Swift.h"
19 | #import "ORGIFRightClickMenuMaker.h"
20 | #import
21 |
22 | @interface GIF()
23 | @property (nonatomic, strong, readwrite) NSDate *dateAdded;
24 | @end
25 |
26 | @interface ORGIFController ()
27 | @property(nonatomic, strong) IBOutlet ORWindowTitleDecorationController *windowDecorationController;
28 |
29 | @property(nonatomic, copy) NSURL *lastUserSelectedDirectory;
30 | @property(nonatomic, copy) ORGIFRightClickMenuMaker *menuMaker;
31 | @end
32 |
33 | @implementation ORGIFController {
34 | NSObject *_currentSource;
35 | NSSet *_starred;
36 | NSString *_gifPath;
37 |
38 | CALayer *_headerLayer;
39 | }
40 |
41 | - (void)getGIFsFromSourceString:(NSString *)string {
42 | BOOL showGiphyLogo = NO;
43 |
44 | if([string rangeOfString:@"/r/"].location != NSNotFound) {
45 | _currentSource = _redditController;
46 | [_redditController setSubreddit:string];
47 | }
48 |
49 | else if([string rangeOfString:@".tumblr"].location != NSNotFound) {
50 | _currentSource = _tumblrController;
51 | [_tumblrController setTumblrURL:string];
52 |
53 | } else if([string isEqualToString:@"STARRED"]){
54 | _currentSource = _starredController;
55 | _starredController.gifController = self;
56 | [_starredController reloadData];
57 |
58 | } else {
59 | _currentSource = _searchController;
60 | [_searchController setQuery:string];
61 | [_searchController setAPIKey:[GifsKeys new].giphyAPIKey];
62 | showGiphyLogo = YES;
63 | }
64 |
65 | [self.windowDecorationController showGiphyLogo:showGiphyLogo];
66 | [self getNextGIFs];
67 | [self.collectionView reloadData];
68 | self.sectionTitle.stringValue = string;
69 | }
70 |
71 | - (void)awakeFromNib {
72 | self.webView.drawsBackground = NO;
73 | self.webView.frame = self.webView.superview.bounds;
74 |
75 | [self.collectionView.superview setPostsBoundsChangedNotifications:YES];
76 | [[NSNotificationCenter defaultCenter] addObserver:self
77 | selector:@selector(myTableClipBoundsChanged:)
78 | name:NSViewBoundsDidChangeNotification object:self.collectionView.superview];
79 |
80 | [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
81 |
82 | [self loadStarred];
83 | }
84 |
85 | - (void)loadStarred {
86 | NSString *path = [[NSFileManager defaultManager] pathForPrivateFile:@"starred.data"];
87 | NSSet *data = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
88 |
89 | if (!data) data = [NSSet set];
90 | _starred = [data mutableCopy];
91 | }
92 |
93 | - (void)saveStarred {
94 | NSString *path = [[NSFileManager defaultManager] pathForPrivateFile:@"starred.data"];
95 | [NSKeyedArchiver archiveRootObject:_starred toFile:path];
96 | }
97 |
98 | - (void)handleURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent
99 | {
100 | NSString *appleURL = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
101 | NSString *download = [appleURL substringBetween:@"?dl=" and:@"***thumb"];
102 | NSString *thumbnail = [appleURL substringBetween:@"***thumb=" and:@"&***source_title"];
103 | NSString *source = [[appleURL componentsSeparatedByString:@"&***source="] lastObject];
104 | NSString *sourceTitle = [appleURL substringBetween:@"***source_title=" and:@"&***source="];
105 | sourceTitle = [sourceTitle stringByRemovingPercentEncoding];
106 |
107 | GIF *gif = [[GIF alloc] initWithDownloadURL:download thumbnail:thumbnail source:source sourceTitle:sourceTitle];
108 | gif.dateAdded = [NSDate date];
109 |
110 | if([_starred containsObject:gif]){
111 | NSMutableSet *mutableSet = [NSMutableSet setWithSet:_starred];
112 | [mutableSet removeObject:gif];
113 | _starred = mutableSet;
114 | } else {
115 | _starred = [_starred setByAddingObject:gif];
116 | }
117 |
118 | [self saveStarred];
119 | [_starredController reloadData];
120 | [_menuController reloadFavourites];
121 |
122 | }
123 |
124 | - (void)myTableClipBoundsChanged:(NSNotification *)notification
125 | {
126 | NSClipView *clipView = [notification object];
127 | NSRect newClipBounds = [clipView bounds];
128 | CGFloat height = [(NSScrollView *)_collectionView.superview.superview contentSize].height;
129 |
130 | if (CGRectGetMinY(newClipBounds) + CGRectGetHeight(newClipBounds) < height + 20) {
131 | [self getNextGIFs];
132 | }
133 |
134 | }
135 |
136 | - (void)gotNewGIFs
137 | {
138 | NSClipView *clipView = (NSClipView *)[self.collectionView superview];
139 |
140 | CGFloat clipViewVisibleHeight = CGRectGetHeight(clipView.documentVisibleRect);
141 | CGFloat clipViewDocumentHeight = CGRectGetHeight([clipView.documentView bounds]);
142 | if (clipViewVisibleHeight == clipViewDocumentHeight) {
143 | [self getNextGIFs];
144 | }
145 |
146 | }
147 |
148 | - (void)getNextGIFs
149 | {
150 | [_currentSource getNextGIFs:^(NSArray *newGIFs, NSError *error) {
151 | [self.collectionView reloadData];
152 | [self gotNewGIFs];
153 |
154 | if (!self.currentGIF){
155 | NSIndexSet *set = [NSIndexSet indexSetWithIndex:0];
156 | [self.collectionView setSelectionIndexes:set byExtendingSelection:YES];
157 | }
158 | }];
159 | }
160 |
161 | -(NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView *)aBrowser
162 | {
163 | return _currentSource.numberOfGifs;
164 | }
165 |
166 | -(id)imageBrowser:(IKImageBrowserView *)aBrowser itemAtIndex:(NSUInteger)index
167 | {
168 | return [_currentSource gifAtIndex:index];
169 | }
170 |
171 | -(void)imageBrowser:(IKImageBrowserView *)aBrowser cellWasRightClickedAtIndex:(NSUInteger)index withEvent:(NSEvent *)event
172 | {
173 | _menuMaker = [[ORGIFRightClickMenuMaker alloc] initWithGIF:self.currentGIF];
174 | [NSMenu popUpContextMenu:self.menuMaker.menu withEvent:event forView:aBrowser];
175 | }
176 |
177 | - (void) imageBrowserSelectionDidChange:(IKImageBrowserView *) aBrowser;
178 | {
179 | NSInteger index = aBrowser.selectionIndexes.firstIndex;
180 |
181 | if (index != NSNotFound) {
182 | GIF *gif = [_currentSource gifAtIndex:index];
183 | _currentGIF = gif;
184 |
185 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"gif_template" ofType:@"html"];
186 | NSString *html = [NSString stringWithContentsOfFile:filePath encoding:NSASCIIStringEncoding error:nil];
187 | NSString *address = gif.downloadURL.absoluteString ?: @"";
188 | html = [html stringByReplacingOccurrencesOfString:@"{{OR_IMAGE_URL}}" withString:address];
189 | html = [html stringByReplacingOccurrencesOfString:@"{{OR_THUMB_URL}}" withString:[gif.imageRepresentation absoluteString] ?: @""];
190 | html = [html stringByReplacingOccurrencesOfString:@"{{OR_SOURCE_URL}}" withString:[gif.sourceURL absoluteString] ?: @""];
191 | html = [html stringByReplacingOccurrencesOfString:@"{{OR_SOURCE_TITLE}}" withString:gif.sourceTitle ?: @""];
192 |
193 | self.gifTitle.stringValue = gif.sourceTitle;
194 |
195 | if ([_starredController hasGIFWithDownloadAddress:address]) {
196 | html = [html stringByReplacingOccurrencesOfString:@" id='star' " withString:@" id='star' class='active' "];
197 | }
198 |
199 | if (html) {
200 | NSString *title = [@" " stringByAppendingString:gif.sourceTitle];
201 | [self.openGIFContextButton setTitle:title];
202 | [[_webView mainFrame] loadHTMLString:html baseURL:nil];
203 | }
204 | }
205 | }
206 | //
207 | // - (NSUInteger) numberOfGroupsInImageBrowser:(IKImageBrowserView *) aBrowser
208 | // {
209 | // return 1;
210 | // }
211 | //
212 | // - (NSDictionary *) imageBrowser:(IKImageBrowserView *)aBrowser groupAtIndex:(NSUInteger)index
213 | // {
214 | // CALayer *headerLayer = [CALayer layer];
215 | // headerLayer.bounds = CGRectMake(0.0, 0.0, 1.0, 70.0);
216 | // headerLayer.backgroundColor = [NSColor whiteColor].CGColor;
217 | //
218 | // NSValue *range = [NSValue valueWithRange:NSMakeRange(0, [self numberOfItemsInImageBrowser:aBrowser])];
219 | //
220 | // return @{
221 | // IKImageBrowserGroupStyleKey: @(IKGroupDisclosureStyle),
222 | // IKImageBrowserGroupHeaderLayer: headerLayer,
223 | // IKImageBrowserGroupRangeKey: range
224 | // };
225 | // }
226 |
227 | - (NSString *)gifFilePath {
228 | return _gifPath;
229 | }
230 |
231 | - (IBAction)openCurrentGIF:(NSButton *)sender
232 | {
233 | [[NSWorkspace sharedWorkspace] openURL:self.currentGIF.sourceURL];
234 | }
235 |
236 | - (IBAction)togglePopover:(NSButton *)sender
237 | {
238 | if (!self.createSourcePopover.isShown) {
239 | self.createSourcePopover.behavior = NSPopoverBehaviorTransient;
240 | [self.createSourcePopover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
241 |
242 | } else {
243 | [self.createSourcePopover close];
244 | }
245 | }
246 |
247 | #pragma mark - ORImageBrowserViewDelegate
248 |
249 | - (NSURL *)URLForCurrentGIF
250 | {
251 | return [self.currentGIF downloadURL];
252 | }
253 |
254 | - (NSURL *)URLForCurrentGIFContext
255 | {
256 | return [self.currentGIF sourceURL];
257 | }
258 |
259 | - (NSString *)sourceTitleForCurrentGIF
260 | {
261 | return self.currentGIF.sourceTitle;
262 | }
263 |
264 | @end
265 |
--------------------------------------------------------------------------------
/objc/GIFs/ORGIFRightClickMenuMaker.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORGIFRightClickMenuMaker.h
3 | // GIFs
4 | //
5 | // Created by Orta on 8/20/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | @interface ORGIFRightClickMenuMaker : NSObject
10 |
11 | - (instancetype)initWithGIF:(GIF *)gif;
12 | @property (readonly, nonatomic, strong) GIF *gif;
13 |
14 | - (NSMenu *)menu;
15 | - (NSArray *)menuItemsWithImageCopyItem:(NSMenuItem *)item;
16 | @end
17 |
--------------------------------------------------------------------------------
/objc/GIFs/ORGIFRightClickMenuMaker.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORGIFRightClickMenuMaker.m
3 | // GIFs
4 | //
5 | // Created by Orta on 8/20/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORGIFRightClickMenuMaker.h"
10 | #import "ORGIFActionsController.h"
11 |
12 | @interface ORGIFRightClickMenuMaker()
13 | @property (readonly, nonatomic, copy) NSArray *sharingServices;
14 |
15 | @end
16 |
17 | @implementation ORGIFRightClickMenuMaker
18 |
19 | - (instancetype)initWithGIF:(GIF *)gif
20 | {
21 | self = [super init];
22 | if (!self) return nil;
23 |
24 | _gif = gif;
25 |
26 | return self;
27 | }
28 |
29 | - (NSMenu *)menu;
30 | {
31 | NSMenu *menu = [[NSMenu alloc] initWithTitle:@"menu"];
32 | [menu setAutoenablesItems:NO];
33 |
34 | for (NSMenuItem *item in [self menuItemsWithImageCopyItem:nil]) {
35 | [menu addItem:item];
36 | }
37 | return menu;
38 | }
39 |
40 | - (NSArray *)menuItemsWithImageCopyItem:(NSMenuItem *)copyItem
41 | {
42 | NSMutableArray *menuItems = [NSMutableArray array];
43 |
44 | NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Copy GIF URL to Clipboard" action: @selector(copyURL) keyEquivalent:@"c"];
45 | [item setTarget:self];
46 | [menuItems addObject:item];
47 |
48 | item = [[NSMenuItem alloc] initWithTitle:@"Copy Image Markdown" action: @selector(copyMarkdown) keyEquivalent:@"C"];
49 | [item setTarget:self];
50 | [menuItems addObject:item];
51 |
52 | if (copyItem) {
53 | [menuItems addObject:copyItem];
54 | }
55 |
56 | [menuItems addObject:[NSMenuItem separatorItem]];
57 | item = [[NSMenuItem alloc] initWithTitle:@"Open GIF in Browser" action:@selector(openInBrowser) keyEquivalent:@"b"];
58 | item.target = self;
59 | [menuItems addObject:item];
60 |
61 | if (self.gif.sourceURL) {
62 | item = [[NSMenuItem alloc] initWithTitle:@"Open GIF Context" action:@selector(openContext) keyEquivalent:@"o"];
63 | item.target = self;
64 | [menuItems addObject:item];
65 | }
66 |
67 | [menuItems addObject:[NSMenuItem separatorItem]];
68 | item = [[NSMenuItem alloc] initWithTitle:@"Download GIF" action:@selector(downloadGIF) keyEquivalent:@"s"];
69 | item.target = self;
70 | [menuItems addObject:item];
71 |
72 | [menuItems addObject:[NSMenuItem separatorItem]];
73 | item = [[NSMenuItem alloc] initWithTitle:@"Post to @RandoGIFs" action:@selector(postToRando) keyEquivalent:@"r"];
74 | item.target = self;
75 | [menuItems addObject:item];
76 |
77 | item = [[NSMenuItem alloc] initWithTitle:@"Send to @orta" action:@selector(postToOrta) keyEquivalent:@"O"];
78 | item.target = self;
79 | [menuItems addObject:item];
80 |
81 | [menuItems addObject:[NSMenuItem separatorItem]];
82 |
83 | NSArray *sharingServiceIDs = @[NSSharingServiceNamePostOnFacebook, NSSharingServiceNamePostOnTwitter, NSSharingServiceNamePostOnSinaWeibo, NSSharingServiceNamePostOnTencentWeibo, NSSharingServiceNamePostOnLinkedIn, NSSharingServiceNameComposeEmail, NSSharingServiceNameComposeMessage];
84 |
85 | _sharingServices = [NSSharingService sharingServicesForItems:sharingServiceIDs];
86 | for (NSSharingService *currentService in self.sharingServices) {
87 | NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:currentService.title action:@selector(share:) keyEquivalent:@""];
88 | item.image = currentService.image;
89 | item.representedObject = currentService;
90 | item.target = self;
91 |
92 | currentService.delegate = self;
93 | [menuItems addObject:item];
94 | }
95 |
96 | return [NSArray arrayWithArray:menuItems];
97 |
98 | }
99 |
100 | - (void)share:(NSMenuItem *)share
101 | {
102 | NSSharingService *service = share.representedObject;
103 | [service performWithItems:@[@"", self.gif.downloadURL]];
104 | }
105 |
106 |
107 | - (void)postToOrta
108 | {
109 | [ORGIFActionsController tweetOrtaLinkToURL:self.gif.downloadURL];
110 | }
111 |
112 | - (void)postToRando
113 | {
114 | [ORGIFActionsController tweetOutLinkToURL:self.gif.downloadURL];
115 | }
116 |
117 | - (void)downloadGIF
118 | {
119 | [ORGIFActionsController downloadGIFWithURL:self.gif.downloadURL completion:nil];
120 | }
121 |
122 | - (void)copyURL
123 | {
124 | [ORGIFActionsController copyGIFDownloadURLToClipboard:self.gif.downloadURL];
125 | }
126 |
127 | - (void)copyMarkdown
128 | {
129 | [ORGIFActionsController copyGIFMarkdownToClipboardWithSourceTitle:self.gif.sourceTitle
130 | downloadURL:self.gif.downloadURL];
131 | }
132 |
133 | - (void)openInBrowser
134 | {
135 | [ORGIFActionsController openGIFDownloadURLInBrowser:self.gif.downloadURL];
136 | }
137 |
138 | - (void)openContext
139 | {
140 | [ORGIFActionsController openGIFContextURLInBrowser:self.gif.sourceURL];
141 | }
142 |
143 | @end
144 |
--------------------------------------------------------------------------------
/objc/GIFs/ORImageBrowserView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORImageBrowserView.h
3 | // GIFs
4 | //
5 | // Created by Orta on 8/24/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol ORImageBrowserViewDelegate
12 |
13 | - (NSURL *)URLForCurrentGIF;
14 | - (NSURL *)URLForCurrentGIFContext;
15 | - (NSString *)sourceTitleForCurrentGIF;
16 |
17 | @end
18 |
19 | @interface ORImageBrowserView : IKImageBrowserView
20 |
21 | @property (nonatomic, weak) IBOutlet id gifDelegate;
22 |
23 | @end
24 |
25 | @interface ORImageBrowserCell : IKImageBrowserCell
26 |
27 | @end
--------------------------------------------------------------------------------
/objc/GIFs/ORImageBrowserView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORImageBrowserView.m
3 | // GIFs
4 | //
5 | // Created by Orta on 8/24/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORImageBrowserView.h"
10 | #import "ORGIFActionsController.h"
11 |
12 | static CGFloat const ORImageBrowserMargin = 3;
13 |
14 | @implementation ORImageBrowserView
15 |
16 | - (IKImageBrowserCell *) newCellForRepresentedItem:(id) cell
17 | {
18 | return [[ORImageBrowserCell alloc] init];
19 | }
20 |
21 | - (void)copy:(id)sender
22 | {
23 | [ORGIFActionsController copyGIFDownloadURLToClipboard:[self.gifDelegate URLForCurrentGIF]];
24 | }
25 |
26 | - (void)keyDown:(NSEvent *)theEvent
27 | {
28 | NSURL *gif = [self.gifDelegate URLForCurrentGIF];
29 |
30 | if (theEvent.modifierFlags & NSCommandKeyMask) {
31 | if ([theEvent.characters isEqualToString:@"b"]) { // Command+b - Open in browser
32 | [ORGIFActionsController openGIFDownloadURLInBrowser:gif];
33 | } else if ([theEvent.characters isEqualToString:@"o"]) { // Command+o - Open GIF context in browser
34 | [ORGIFActionsController openGIFContextURLInBrowser:gif];
35 | } else if ([theEvent.characters isEqualToString:@"s"]) { // Command+s - Save GIF to disk
36 | [ORGIFActionsController downloadGIFWithURL:gif completion:nil];
37 | } else if ([theEvent.characters isEqualToString:@"r"]) { // Command+r - Send Rando GIF
38 | [ORGIFActionsController tweetOutLinkToURL:gif];
39 | }
40 |
41 | }
42 |
43 | else if ((theEvent.modifierFlags & NSCommandKeyMask) && (theEvent.modifierFlags & NSShiftKeyMask)) {
44 | if ([theEvent.characters isEqualToString:@"c"]) { // Command+Shift+c - Copy GIF markdown to clipboard
45 | [ORGIFActionsController copyGIFMarkdownToClipboardWithSourceTitle:[self.gifDelegate sourceTitleForCurrentGIF]
46 | downloadURL:[self.gifDelegate URLForCurrentGIF]];
47 |
48 | } else if ([theEvent.characters isEqualToString:@"o"]) { // Command+r - Send Rando GIF
49 | [ORGIFActionsController tweetOrtaLinkToURL:gif];
50 | }
51 | }
52 |
53 | else {
54 | [super keyDown:theEvent];
55 | }
56 | }
57 |
58 | @end
59 |
60 | @implementation ORImageBrowserCell
61 |
62 | - (NSRect)imageFrame
63 | {
64 | NSRect imageFrame = [super imageFrame];
65 |
66 | if (NSIsEmptyRect(imageFrame)) {
67 | return NSZeroRect;
68 | }
69 |
70 | CGFloat aspectRatio = imageFrame.size.width / imageFrame.size.height;
71 |
72 | if (aspectRatio == 1.0f) {
73 | return imageFrame;
74 | }
75 |
76 | NSRect containerFrame = [self imageContainerFrame];
77 |
78 | if (NSIsEmptyRect(containerFrame)) {
79 | return NSZeroRect;
80 | }
81 |
82 | CGFloat containerAspectRatio = containerFrame.size.width / containerFrame.size.height;
83 |
84 | if (containerAspectRatio > aspectRatio) {
85 | imageFrame.size.height = containerFrame.size.height;
86 | imageFrame.origin.y = containerFrame.origin.y;
87 | imageFrame.size.width = imageFrame.size.height * aspectRatio;
88 | imageFrame.origin.x = containerFrame.origin.x + (containerFrame.size.width - imageFrame.size.width) / 2.0f;
89 | } else {
90 | imageFrame.size.width = containerFrame.size.width;
91 | imageFrame.origin.x = containerFrame.origin.x;
92 | imageFrame.size.height = imageFrame.size.width / aspectRatio;
93 | imageFrame.origin.y = containerFrame.origin.y + (containerFrame.size.height - imageFrame.size.height) / 2.0f;
94 | }
95 |
96 | return imageFrame;
97 | }
98 |
99 | - (NSRect) selectionFrame
100 | {
101 | return NSInsetRect([self frame], -ORImageBrowserMargin, -ORImageBrowserMargin);
102 | }
103 |
104 | - (CALayer *) layerForType:(NSString*) type
105 | {
106 | NSRect frame = [self frame];
107 |
108 | if(type == IKImageBrowserCellSelectionLayer){
109 |
110 | CALayer *selectionLayer = [CALayer layer];
111 | selectionLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
112 |
113 | NSColor *color = [NSColor selectedMenuItemColor];
114 | [selectionLayer setBorderColor:color.CGColor];
115 |
116 | [selectionLayer setBorderWidth:ORImageBrowserMargin];
117 | [selectionLayer setCornerRadius:0];
118 |
119 | return selectionLayer;
120 | }
121 |
122 | return [super layerForType:type];
123 | }
124 |
125 | @end
126 |
--------------------------------------------------------------------------------
/objc/GIFs/ORImageView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORImaageView.h
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ORImageView : IKImageView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/objc/GIFs/ORImageView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORImaageView.m
3 | // GIFs
4 | //
5 | // http://blog.pcitron.fr/2010/12/14/play-an-animated-gif-with-an-ikimageview/
6 |
7 | #import "ORImageView.h"
8 |
9 | @implementation ORImageView
10 |
11 | -(void)awakeFromNib {
12 | // create an overlay for the image (which is used to play animated gifs)
13 | // EDIT: well, don't do that here, due to some initialization orders
14 | // problem, it might gives an error and not create the overlay
15 | // I leave that line here for the records ^^
16 | //[self setOverlay:[CALayer layer] forType:IKOverlayTypeImage];
17 |
18 | // NOTE: calling this before anything else seems to fix a lot of
19 | // problems ... maybe it's initializing a few things internally
20 | // on the first call ...
21 | [super setImageWithURL:nil];
22 | }
23 |
24 | -(BOOL)isGIF:(NSString *)path
25 | {
26 | return YES;
27 | // checks if the path points to a GIF image
28 | NSString * pathExtension = [[path pathExtension] lowercaseString];
29 | return [pathExtension isEqualToString:@"gif"];
30 | }
31 |
32 | -(void)setImageWithURL:(NSURL *)url
33 | {
34 | // EDIT: this is where we create the overlay now, but only if it doesn't
35 | // already exists.
36 | // checks if a layer is already set
37 | if ([self overlayForType:IKOverlayTypeImage] == nil)
38 | [self setOverlay:[CALayer layer] forType:IKOverlayTypeImage];
39 |
40 | // remove the overlay animation
41 | [[self overlayForType:IKOverlayTypeImage] removeAllAnimations];
42 |
43 | // check if it's a gif
44 | if ([self isGIF:[url path]] == YES)
45 | {
46 | // loads the image
47 | NSImage * image = [[NSImage alloc] initWithContentsOfFile:[url path]];
48 |
49 | // get the image representations, and iterate through them
50 | NSArray * reps = [image representations];
51 | for (NSImageRep * rep in reps) {
52 | // find the bitmap representation
53 | if ([rep isKindOfClass:[NSBitmapImageRep class]] == YES) {
54 | // get the bitmap representation
55 | NSBitmapImageRep * bitmapRep = (NSBitmapImageRep *)rep;
56 |
57 | // get the number of frames. If it's 0, it's not an animated gif, do nothing
58 | int numFrame = [[bitmapRep valueForProperty:NSImageFrameCount] intValue];
59 | if (numFrame == 0)
60 | break;
61 |
62 | // create a value array which will contains the frames of the animation
63 | NSMutableArray * values = [NSMutableArray array];
64 |
65 | // loop through the frames (animationDuration is the duration of the whole animation)
66 | float animationDuration = 0.0f;
67 | for (int i = 0; i < numFrame; ++i)
68 | {
69 | // set the current frame
70 | [bitmapRep setProperty:NSImageCurrentFrame withValue:[NSNumber numberWithInt:i]];
71 |
72 | // this part is optional. For some reasons, the NSImage class often loads a GIF with
73 | // frame times of 0, so the GIF plays extremely fast. So, we check the frame duration, and if it's
74 | // less than a threshold value, we set it to a default value of 1/20 second.
75 | if ([[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue] < 0.000001f)
76 | [bitmapRep setProperty:NSImageCurrentFrameDuration withValue:[NSNumber numberWithFloat:1.0f / 20.0f]];
77 |
78 | // add the CGImageRef to this frame to the value array
79 | [values addObject:(id)[bitmapRep CGImage]];
80 |
81 | // update the duration of the animation
82 | animationDuration += [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue];
83 | }
84 |
85 | // create and setup the animation (this is pretty straightforward)
86 | CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
87 | [animation setValues:values];
88 | [animation setCalculationMode:@"discrete"];
89 | [animation setDuration:animationDuration];
90 | [animation setRepeatCount:HUGE_VAL];
91 |
92 | // add the animation to the layer
93 | [[self overlayForType:IKOverlayTypeImage] addAnimation:animation forKey:@"contents"];
94 |
95 | // stops at the first valid representation
96 | break;
97 | }
98 | }
99 | }
100 |
101 | // calls the super setImageWithURL method to handle standard images
102 | [super setImageWithURL:url];
103 | }
104 |
105 | @end
106 |
--------------------------------------------------------------------------------
/objc/GIFs/ORMenuController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORMenuController.h
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ORGIFController.h"
11 | #import "ORSimpleSourceListView.h"
12 |
13 | @class ORStarredSourceController;
14 |
15 | @interface ORMenuController : NSObject
16 |
17 | @property (weak) IBOutlet ORGIFController *gifViewController;
18 | @property (weak) IBOutlet ORSimpleSourceListView *menuTableView;
19 | @property (weak) IBOutlet ORStarredSourceController *starredController;
20 |
21 | @property (unsafe_unretained) IBOutlet NSWindow *window;
22 | @property (weak) IBOutlet NSView *windowToolbar;
23 | @property (weak) IBOutlet NSSplitView *mainSplitView;
24 |
25 | @property (weak) IBOutlet NSTextField *searchBar;
26 |
27 | - (IBAction)makeSearchFieldFirstResponder:(id)sender;
28 | - (void)addNewSubreddit:(NSString *)subreddit;
29 | - (void)addNewTumblr:(NSString *)tumblr;
30 | - (void)reloadFavourites;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/objc/GIFs/ORMenuController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORMenuController.m
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORMenuController.h"
10 | #import
11 | #import "ORStarredSourceController.h"
12 |
13 | NS_ENUM(NSUInteger, ORMenuTitle){
14 | ORMenuTitleStar,
15 | ORMenuTitleSearch,
16 | ORMenuTitleReddit,
17 | ORMenuTitleTumblr
18 | };
19 |
20 | @interface ORMenuItem : NSObject
21 | + (id)itemWithName:(NSString *)name address:(NSString *)address;
22 |
23 | @property (copy, nonatomic) NSString *name;
24 | @property (copy, nonatomic) NSString *address;
25 | @end
26 |
27 | @implementation ORMenuItem
28 |
29 | + (id)itemWithName:(NSString *)name address:(NSString *)address {
30 | ORMenuItem *item = [[ORMenuItem alloc] init];
31 | item.name = name;
32 | item.address = address;
33 | return item;
34 | }
35 |
36 | #define kNameKey @"name"
37 | #define kAddressKey @"address"
38 |
39 | - (void)encodeWithCoder:(NSCoder *)encoder {
40 | [encoder encodeObject:_name forKey:kNameKey];
41 | [encoder encodeObject:_address forKey:kAddressKey];
42 | }
43 |
44 | - (id)initWithCoder:(NSCoder *)decoder {
45 | NSString *name = [decoder decodeObjectForKey:kNameKey];
46 | NSString *address = [decoder decodeObjectForKey:kAddressKey];
47 | return [self.class itemWithName:name address:address];
48 | }
49 |
50 | @end
51 |
52 | @implementation ORMenuController {
53 | NSMutableArray *_redditSources;
54 | NSMutableArray *_tumblrSources;
55 |
56 | NSMutableArray *_searches;
57 | }
58 |
59 | - (id) init {
60 | self = [super init];
61 | if (!self) return nil;
62 |
63 | _searches = [@[] mutableCopy];
64 |
65 | [self loadReddit];
66 | [self loadTumblr];
67 |
68 | return self;
69 | }
70 |
71 | - (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor {
72 | NSTextField *searchField = (NSTextField *)control;
73 | [_searches insertObject:searchField.stringValue atIndex:0];
74 | [searchField setStringValue:@""];
75 |
76 | [_menuTableView reloadData];
77 |
78 | [_menuTableView setSelectedIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
79 | return YES;
80 | }
81 |
82 | - (void)reloadFavourites
83 | {
84 |
85 | NSTableRowView *row = [self.menuTableView rowViewAtRow:1 makeIfNecessary:NO];
86 | NSTableCellView *cell = [row viewAtColumn:0];
87 |
88 | CABasicAnimation *anime = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
89 | anime.fromValue = (id)[cell.layer backgroundColor];
90 | anime.toValue = (id) [NSColor colorWithCalibratedRed:1.000 green:0.965 blue:0.722 alpha:1.000].CGColor;
91 | anime.duration = 0.15;
92 | anime.autoreverses = YES;
93 |
94 | [cell.layer addAnimation:anime forKey:@"backgroundColor"];
95 | cell.textField.stringValue = [self titleForStars];
96 | }
97 |
98 | #pragma mark -
99 | #pragma mark ORSourceListDataSource
100 |
101 |
102 | - (NSImage *)sourceList:(ORSimpleSourceListView *)sourceList imageForHeaderInSection:(NSUInteger)section {
103 | switch (section) {
104 | case ORMenuTitleSearch:
105 | return [NSImage imageNamed:@"SearchWhite"];
106 |
107 | case ORMenuTitleReddit:
108 | return [NSImage imageNamed:@"RedditWhite"];
109 |
110 | case ORMenuTitleTumblr:
111 | return [NSImage imageNamed:@"tumblr_t_active"];
112 |
113 | case ORMenuTitleStar:
114 | return [NSImage imageNamed:@"tick"];
115 | }
116 |
117 | return nil;
118 | }
119 |
120 | - (NSString *)sourceList:(ORSimpleSourceListView *)sourceList titleOfHeaderForSection:(NSUInteger)section {
121 | switch (section) {
122 | case ORMenuTitleSearch:
123 | return @"Search";
124 |
125 | case ORMenuTitleReddit:
126 | return @"Reddit";
127 |
128 | case ORMenuTitleTumblr:
129 | return @"Tumblr";
130 |
131 | case ORMenuTitleStar:
132 | return @"Starred";
133 | }
134 |
135 | return @"";
136 | }
137 |
138 | - (ORSourceListItem *)sourceList:(ORSimpleSourceListView *)sourceList sourceListItemForIndexPath:(NSIndexPath *)indexPath {
139 | ORSourceListItem *item = [[ORSourceListItem alloc] init];
140 | ORMenuItem *menuItem = nil;
141 | item.rightButtonImage = @"close";
142 | item.rightButtonActiveImage = @"close_active";
143 |
144 | switch (indexPath.section) {
145 | case ORMenuTitleSearch:
146 | item.title = _searches[indexPath.row];
147 | item.thumbnail = @"Search";
148 | item.selectedThumbnail = @"SearchWhite";
149 | return item;
150 |
151 | case ORMenuTitleReddit:
152 | menuItem = _redditSources[indexPath.row];
153 | item.title = [menuItem name];
154 | item.thumbnail = @"Reddit";
155 | item.selectedThumbnail = @"RedditWhite";
156 |
157 | return item;
158 |
159 | case ORMenuTitleTumblr:
160 | menuItem = _tumblrSources[indexPath.row];
161 | item.title = menuItem.name;
162 | item.thumbnail = @"tumblr_t";
163 | item.selectedThumbnail = @"tumblr_t_active";
164 |
165 | return item;
166 |
167 | case ORMenuTitleStar:
168 | item.title = [self titleForStars];
169 | return item;
170 | }
171 |
172 | return nil;
173 | }
174 |
175 | - (NSString *)titleForStars
176 | {
177 | NSInteger count = [self.starredController numberOfGifs];
178 | switch (count) {
179 | case 0:
180 | return @"No ⭐s";
181 | case 1:
182 | return @"⭐";
183 | case 2:
184 | return @"⭐⭐";
185 | case 3:
186 | return @"⭐⭐⭐";
187 | case 4:
188 | return @"⭐⭐⭐⭐";
189 | case 5:
190 | return @"⭐⭐⭐⭐⭐";
191 | default:
192 | return [NSString stringWithFormat:@"%li ⭐s", (long)count];
193 | }
194 | }
195 |
196 | - (NSUInteger)sourceList:(ORSimpleSourceListView *)sourceList numberOfRowsInSection:(NSUInteger)section {
197 | switch (section) {
198 | case ORMenuTitleSearch:
199 | return _searches.count;
200 |
201 | case ORMenuTitleReddit:
202 | return _redditSources.count;
203 |
204 | case ORMenuTitleTumblr:
205 | return _tumblrSources.count;
206 |
207 | case ORMenuTitleStar:
208 | return 1;
209 | }
210 | return 0;
211 | }
212 |
213 | - (NSUInteger)numberOfSectionsInSourceList:(ORSimpleSourceListView *)sourceList {
214 | return 4;
215 | }
216 |
217 | #pragma mark -
218 | #pragma mark ORSourceListDelegate
219 |
220 | - (void)sourceList:(ORSimpleSourceListView *)sourceList selectionDidChangeToIndexPath:(NSIndexPath *)indexPath {
221 | NSUInteger index = indexPath.row;
222 | ORMenuItem *item = nil;
223 |
224 | switch (indexPath.section) {
225 | case ORMenuTitleSearch:
226 | [_gifViewController getGIFsFromSourceString:_searches[index]];
227 | break;
228 |
229 | case ORMenuTitleReddit:
230 | item = _redditSources[index];
231 | [_gifViewController getGIFsFromSourceString:item.name];
232 | break;
233 |
234 | case ORMenuTitleTumblr:
235 | item = _tumblrSources[index];
236 | [_gifViewController getGIFsFromSourceString:item.address];
237 | break;
238 |
239 | case ORMenuTitleStar:
240 | [_gifViewController getGIFsFromSourceString:@"STARRED"];
241 | }
242 | }
243 |
244 | - (void)sourceList:(ORSimpleSourceListView *)sourceList didClickOnRightButtonForIndexPath:(NSIndexPath *)indexPath
245 | {
246 | NSUInteger index = indexPath.row;
247 |
248 | switch (indexPath.section) {
249 | case ORMenuTitleSearch:
250 | [_searches removeObjectAtIndex:index];
251 | break;
252 |
253 | case ORMenuTitleReddit:
254 | [_redditSources removeObjectAtIndex:index];
255 | [self saveReddit];
256 | break;
257 |
258 | case ORMenuTitleTumblr:
259 | [_tumblrSources removeObjectAtIndex:index];
260 | [self saveTumblr];
261 | break;
262 |
263 | case ORMenuTitleStar:
264 | break;
265 | }
266 |
267 | [sourceList reloadData];
268 | }
269 |
270 | #pragma mark defaults
271 |
272 | - (NSArray *)defaultRedditSources {
273 | return @[
274 | [ORMenuItem itemWithName:@"/r/ReactionGIFs" address:@"reactiongifs"],
275 | [ORMenuItem itemWithName:@"/r/GIFs" address:@"gifs"],
276 | [ORMenuItem itemWithName:@"/r/GIF" address:@"gif"],
277 | [ORMenuItem itemWithName:@"/r/aww_gifs" address:@"aww_gifs"],
278 | [ORMenuItem itemWithName:@"/r/Cinemagraphs" address:@"cinemagraphs"],
279 | [ORMenuItem itemWithName:@"/r/chemicalreactiongifs" address:@"chemicalreactiongifs"],
280 | [ORMenuItem itemWithName:@"/r/perfectloops" address:@"perfectloops"],
281 | [ORMenuItem itemWithName:@"/r/highqualitygifs" address:@"highqualitygifs"],
282 | ];
283 | }
284 |
285 | - (NSArray *)defaultTumblrSources {
286 | return @[
287 | [ORMenuItem itemWithName:@"What Should We Call Me" address:@"http://whatshouldwecallme.tumblr.com"],
288 | [ORMenuItem itemWithName:@"Animaly GIFs" address:@"http://animalygifs.tumblr.com"],
289 | [ORMenuItem itemWithName:@"GIF Movie" address:@"http://gifmovie.tumblr.com"],
290 | [ORMenuItem itemWithName:@"Reality TV GIFs" address:@"http://realitytvgifs.tumblr.com"],
291 | [ORMenuItem itemWithName:@"Mr GIF" address:@"http://mr-gif.com"],
292 | [ORMenuItem itemWithName:@"Beer Labels In Motion" address:@"http://beerlabelsinmotion.tumblr.com"],
293 | [ORMenuItem itemWithName:@"Bees & Bombs" address:@"http://beesandbombs.tumblr.com"]
294 | ];
295 | }
296 |
297 | - (void)loadTumblr {
298 | NSString *path = [[NSFileManager defaultManager] pathForPrivateFile:@"tumblr.data"];
299 | NSArray *data = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
300 |
301 | if (!data) data = [self defaultTumblrSources];
302 | _tumblrSources = [data mutableCopy];
303 | }
304 |
305 | - (void)saveTumblr {
306 | NSString *path = [[NSFileManager defaultManager] pathForPrivateFile:@"tumblr.data"];
307 | [NSKeyedArchiver archiveRootObject:_tumblrSources toFile:path];
308 | }
309 |
310 | - (void)addNewTumblr:(NSString *)tumblr {
311 | NSString *name = [tumblr stringByReplacingOccurrencesOfString:@"http://" withString:@""];
312 | name = [name stringByReplacingOccurrencesOfString:@".tumblr.com" withString:@""];
313 |
314 | ORMenuItem *item =[ORMenuItem itemWithName:name address:tumblr];
315 | [_tumblrSources addObject:item];
316 | [self.menuTableView reloadData];
317 | [self saveTumblr];
318 | }
319 |
320 |
321 | - (void)loadReddit {
322 | NSString *path = [[NSFileManager defaultManager] pathForPrivateFile:@"reddit.data"];
323 | NSArray *data = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
324 |
325 | if (!data) data = [self defaultRedditSources];
326 | _redditSources = [data mutableCopy];
327 | }
328 |
329 | - (void)saveReddit {
330 | NSString *path = [[NSFileManager defaultManager] pathForPrivateFile:@"reddit.data"];
331 | [NSKeyedArchiver archiveRootObject:_redditSources toFile:path];
332 | }
333 |
334 | - (void)addNewSubreddit:(NSString *)subreddit {
335 | NSString *address = [subreddit stringByReplacingOccurrencesOfString:@"/r/" withString:@""];
336 | address = [address stringByReplacingOccurrencesOfString:@"http://reddit.com/" withString:@""];
337 | address = [address stringByReplacingOccurrencesOfString:@"/" withString:@""];
338 |
339 | ORMenuItem *item =[ORMenuItem itemWithName:subreddit address:address];
340 | [_redditSources addObject:item];
341 | [self.menuTableView reloadData];
342 | [self saveReddit];
343 | }
344 |
345 | - (void)makeSearchFieldFirstResponder:(id)sender
346 | {
347 | [self.searchBar becomeFirstResponder];
348 | }
349 |
350 | @end
351 |
--------------------------------------------------------------------------------
/objc/GIFs/ORMiddleGreyView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORMiddleGreyView.h
3 | // GIFs
4 | //
5 | // Created by Orta on 8/13/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ORMiddleGreyView : NSView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/objc/GIFs/ORMiddleGreyView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORMiddleGreyView.m
3 | // GIFs
4 | //
5 | // Created by Orta on 8/13/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORMiddleGreyView.h"
10 |
11 | @implementation ORMiddleGreyView
12 |
13 | - (void)drawRect:(NSRect)dirtyRect {
14 | [[NSColor colorWithCalibratedRed:0.769 green:0.755 blue:0.756 alpha:1.000] setFill];
15 | NSRectFill(dirtyRect);
16 | [super drawRect:dirtyRect];
17 | }
18 |
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/objc/GIFs/ORSearchTextField.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORSearchTextField.h
3 | // GIFs
4 | //
5 | // Created by Orta on 8/31/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ORSearchTextField : NSTextField
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/objc/GIFs/ORSearchTextField.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORSearchTextField.m
3 | // GIFs
4 | //
5 | // Created by Orta on 8/31/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORSearchTextField.h"
10 |
11 | @implementation ORSearchTextField
12 |
13 | - (void)drawRect:(NSRect)dirtyRect
14 | {
15 | [[NSColor colorWithCalibratedRed:0.150 green:0.140 blue:0.169 alpha:1.000] setFill];
16 | NSRectFill(dirtyRect);
17 | [super drawRect:dirtyRect];
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/objc/GIFs/ORSimpleSourceListView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORSimpleSourceListView.h
3 | // GIFs
4 | //
5 | // Created by orta therox on 20/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class ORSimpleSourceListView, ORSourceListItem;
12 |
13 | @interface NSIndexPath(SourceListExtension)
14 | + (NSIndexPath *)indexPathForRow:(NSInteger)row inSection:(NSInteger)section;
15 | - (NSUInteger)row;
16 | - (NSUInteger)section;
17 | @end
18 |
19 | @interface ORSourceListHeaderView : NSTableCellView
20 | - (id)initWithTitle:(NSString *)title sourceList:(ORSimpleSourceListView *)sourceList;
21 | @end
22 |
23 | @interface ORSourceListItemView : NSTableCellView
24 | - (id)initWithSourceListItem:(ORSourceListItem *)item sourceList:(ORSimpleSourceListView *)sourceList;
25 | @property (assign, nonatomic) BOOL selected;
26 | @property (strong, nonatomic) NSButton *rightImageView;
27 | @end
28 |
29 | @interface ORSourceListRowView : NSTableRowView
30 | @end
31 |
32 | @interface ORSourceListItem : NSObject
33 | @property (strong) NSString *selectedThumbnail;
34 | @property (strong) NSString *thumbnail;
35 | @property (strong) NSString *title;
36 | @property (strong) NSString *rightButtonImage;
37 | @property (strong) NSString *rightButtonActiveImage;
38 | @end
39 |
40 | @protocol ORSourceListDataSource
41 | @required
42 | - (NSUInteger)numberOfSectionsInSourceList:(ORSimpleSourceListView *)sourceList;
43 | - (NSUInteger)sourceList:(ORSimpleSourceListView *)sourceList numberOfRowsInSection:(NSUInteger)section;
44 |
45 | - (NSImage *)sourceList:(ORSimpleSourceListView *)sourceList imageForHeaderInSection:(NSUInteger)section;
46 | - (NSString *)sourceList:(ORSimpleSourceListView *)sourceList titleOfHeaderForSection:(NSUInteger)section;
47 | - (ORSourceListItem *)sourceList:(ORSimpleSourceListView *)sourceList sourceListItemForIndexPath:(NSIndexPath *)indexPath;
48 | @end
49 |
50 | @protocol ORSourceListDelegate
51 | @optional
52 | - (void)sourceList:(ORSimpleSourceListView *)sourceList selectionDidChangeToIndexPath:(NSIndexPath *)indexPath;
53 | - (void)sourceList:(ORSimpleSourceListView *)sourceList didClickOnRightButtonForIndexPath:(NSIndexPath *)indexPath;
54 | @end
55 |
56 |
57 | @interface ORSimpleSourceListView : NSTableView
58 | @property (weak) IBOutlet NSObject *sourceListDelegate;
59 | @property (weak) IBOutlet NSObject *sourceListDataSource;
60 |
61 | @property (strong) NSColor *selectionColor;
62 | @property (strong) NSColor *textColor;
63 | @property (strong) NSColor *highlightedTextColor;
64 |
65 |
66 | - (void)setSelectedIndexPath:(NSIndexPath *)indexPath;
67 | - (void)selectDefaultItem;
68 | @end
69 |
--------------------------------------------------------------------------------
/objc/GIFs/ORSimpleSourceListView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORSimpleSourceListView.m
3 | // GIFs
4 | //
5 | // Created by orta therox on 20/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORSimpleSourceListView.h"
10 |
11 | CGFloat ORCellHeight = 44;
12 | CGFloat ORCellLeftPadding = 12;
13 |
14 | CGFloat ORCellTitleLeftPadding = 42;
15 |
16 | CGFloat ORCellItemLeftPadding = 16;
17 | CGFloat ORCellItemTopPadding = 14;
18 |
19 | CGFloat ORCellImageDimensions = 32;
20 | @class ORSimpleTextField;
21 |
22 | @implementation NSIndexPath(SourceListExtension)
23 | + (NSIndexPath *)indexPathForRow:(NSInteger)row inSection:(NSInteger)section {
24 | NSUInteger indexArr[] = { row, section };
25 | return [NSIndexPath indexPathWithIndexes:indexArr length:2];
26 | }
27 | - (NSUInteger)row { return [self indexAtPosition:0]; }
28 | - (NSUInteger)section { return [self indexAtPosition:1]; }
29 | @end
30 |
31 |
32 |
33 | @interface ORSimpleTextField : NSTextField
34 | @end
35 |
36 | @implementation ORSimpleTextField
37 |
38 | - (BOOL)allowsVibrancy
39 | {
40 | return NO;
41 | }
42 |
43 | @end
44 |
45 | @implementation ORSourceListItem
46 |
47 | @end
48 |
49 | @implementation ORSimpleSourceListView {
50 | // Items stores both titles and items
51 | NSArray *_items;
52 | NSUInteger _currentSelectionIndex;
53 | }
54 |
55 | - (id)initWithFrame:(NSRect)frame {
56 | self = [super initWithFrame:frame];
57 | if (self) {
58 | [self __setup];
59 | }
60 | return self;
61 | }
62 |
63 | - (id)initWithCoder:(NSCoder *)aDecoder {
64 | self = [super initWithCoder:aDecoder];
65 | if (self) {
66 | [self __setup];
67 | }
68 | return self;
69 | }
70 |
71 | - (void)__setup {
72 | self.delegate = self;
73 | self.dataSource = self;
74 | self.focusRingType = NSFocusRingTypeNone;
75 | self.headerView = nil;
76 | self.backgroundColor = [NSColor clearColor];
77 | self.enclosingScrollView.drawsBackground = NO;
78 | self.intercellSpacing = CGSizeMake(0, 0);
79 | self.allowsMultipleSelection = NO;
80 | self.allowsEmptySelection = NO;
81 | self.enclosingScrollView.scrollerStyle = NSScrollerStyleOverlay;
82 |
83 | _currentSelectionIndex = NSNotFound;
84 | }
85 |
86 | - (void)awakeFromNib {
87 | [self reloadData];
88 | }
89 |
90 | - (void)reloadData {
91 | if(_sourceListDataSource){
92 | NSUInteger numberOfSections = [_sourceListDataSource numberOfSectionsInSourceList:self];
93 | if(!numberOfSections) return;
94 |
95 | NSMutableArray *mutableItems = [NSMutableArray array];
96 | for (int i = 0; i < numberOfSections; i++) {
97 | [mutableItems addObject:[_sourceListDataSource sourceList:self titleOfHeaderForSection:i]];
98 | NSUInteger numberOfRows = [_sourceListDataSource sourceList:self numberOfRowsInSection:i];
99 |
100 | for (int j = 0; j < numberOfRows; j++) {
101 | NSIndexPath *currentIndexPath = [NSIndexPath indexPathForRow:j inSection:i];
102 | [mutableItems addObject:[_sourceListDataSource sourceList:self sourceListItemForIndexPath:currentIndexPath]];
103 | }
104 | }
105 | _items = [NSArray arrayWithArray:mutableItems];
106 | }
107 |
108 | [super reloadData];
109 | }
110 |
111 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
112 | return _items.count;
113 | }
114 |
115 | - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
116 | return ORCellHeight;
117 | }
118 |
119 | - (NSView *)tableView:(NSTableView *)tableView
120 | viewForTableColumn:(NSTableColumn *)tableColumn
121 | row:(NSInteger)row {
122 | id item =_items[row];
123 | NSTableCellView *result;
124 | if ([item isMemberOfClass:[ORSourceListItem class]]){
125 | ORSourceListItem *sourceListItem = (ORSourceListItem *)item;
126 | result = [[ORSourceListItemView alloc] initWithSourceListItem:sourceListItem sourceList:self];
127 |
128 | if (row == _currentSelectionIndex) {
129 | [(ORSourceListItemView *)result setSelected:YES];
130 | }
131 |
132 | } else {
133 | NSString *headerString = (NSString *)item;
134 | result = [[ORSourceListHeaderView alloc] initWithTitle:headerString sourceList:self];
135 |
136 | NSIndexPath *indexPath = [self rowToIndexPath:row];
137 | result.imageView.image = [self.sourceListDataSource sourceList:self imageForHeaderInSection:indexPath.section];
138 | }
139 |
140 | return result;
141 | }
142 |
143 | - (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row
144 | {
145 | return [[ORSourceListRowView alloc] init];
146 | }
147 |
148 | - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row {
149 | id item =_items[row];
150 | return [item isKindOfClass:[ORSourceListItem class]];
151 | }
152 |
153 | - (void)selectDefaultItem
154 | {
155 | NSIndexSet *set = [NSIndexSet indexSetWithIndex:4];
156 | [self selectRowIndexes:set byExtendingSelection:NO];
157 | }
158 |
159 | - (void)setSelectedIndexPath:(NSIndexPath *)indexPath {
160 | NSInteger index = [self indexPathToRow:indexPath];
161 | if (index != NSNotFound) {
162 | NSIndexSet *set = [[NSIndexSet alloc] initWithIndex:index];
163 | [self selectRowIndexes:set byExtendingSelection:NO];
164 | }
165 | }
166 |
167 | - (void)selectRowIndexes:(NSIndexSet *)indexes byExtendingSelection:(BOOL)extend {
168 | NSUInteger newIndex = [indexes firstIndex];
169 | if (newIndex != NSNotFound) {
170 | [self _changeSelectionToRow:newIndex];
171 | [super selectRowIndexes:indexes byExtendingSelection:extend];
172 |
173 | id item = _items[newIndex];
174 | if ([item isMemberOfClass:[ORSourceListItem class]]) {
175 | NSIndexPath *path = [self rowToIndexPath:newIndex];
176 | [_sourceListDelegate sourceList:self selectionDidChangeToIndexPath:path];
177 | }
178 | }
179 | }
180 |
181 | - (void)_changeSelectionToRow:(NSInteger)row {
182 | if (_currentSelectionIndex != NSNotFound) {
183 | [self _visuallySelectRowAtIndex:_currentSelectionIndex toState:NO];
184 | }
185 | _currentSelectionIndex = row;
186 | [self _visuallySelectRowAtIndex:row toState:YES];
187 | }
188 |
189 | - (void)_visuallySelectRowAtIndex:(NSUInteger)index toState:(BOOL)state {
190 | ORSourceListRowView *row = [self rowViewAtRow:index makeIfNecessary:NO];
191 | row.selected = state;
192 | }
193 |
194 | - (NSUInteger)indexPathToRow:(NSIndexPath *)path {
195 | NSInteger section = -1;
196 | NSInteger currentRow = -1;
197 | BOOL foundSection = NO;
198 | for (int i = 0; i < _items.count; i++) {
199 | if (![_items[i] isKindOfClass:[ORSourceListItem class]]) {
200 | section++;
201 | if (section == path.section) {
202 | foundSection = YES;
203 | }
204 | }
205 | else if (foundSection) {
206 | currentRow++;
207 | if (currentRow == path.row) {
208 | return i;
209 | }
210 | }
211 | }
212 | return NSNotFound;
213 | }
214 |
215 | - (NSIndexPath *)rowToIndexPath:(NSUInteger)row {
216 | NSInteger indexRow = -1;
217 | NSInteger indexSection = -1;
218 | for (int i = 0; i < (row + 1); i++) {
219 | if ([_items[i] isKindOfClass:[ORSourceListItem class]]) {
220 | indexRow++;
221 | } else {
222 | indexSection++;
223 | indexRow = -1;
224 | }
225 | }
226 | return [NSIndexPath indexPathForRow:indexRow inSection:indexSection];
227 | }
228 |
229 | - (ORSimpleTextField *)textFieldForItems {
230 | ORSimpleTextField *titleLabel = [[ORSimpleTextField alloc] init];
231 | [titleLabel setBezeled:NO];
232 | [titleLabel setDrawsBackground:NO];
233 | [titleLabel setEditable:NO];
234 | [titleLabel setSelectable:NO];
235 | [[titleLabel cell] setBackgroundStyle:NSBackgroundStyleDark];
236 | titleLabel.font = [NSFont systemFontOfSize:13];
237 | titleLabel.textColor = self.textColor;
238 | return titleLabel;
239 | }
240 |
241 | - (NSTextField *)textFieldForHeaders {
242 | NSTextField *headerTextField = [self textFieldForItems];
243 | headerTextField.font = [NSFont boldSystemFontOfSize:13];
244 | headerTextField.textColor = [NSColor colorWithCalibratedRed:0.455 green:0.442 blue:0.459 alpha:1.000];
245 | return headerTextField;
246 | }
247 |
248 |
249 | - (void)tappedOnRightButton:(NSButton *)button {
250 | if ([_sourceListDelegate respondsToSelector:@selector(sourceList:didClickOnRightButtonForIndexPath:)]) {
251 | NSIndexPath *path = [self rowToIndexPath:button.tag];
252 | [_sourceListDelegate sourceList:self didClickOnRightButtonForIndexPath:path];
253 | }
254 | }
255 |
256 | @end
257 |
258 | @implementation ORSourceListHeaderView
259 |
260 | - (id)initWithTitle:(NSString *)title sourceList:(ORSimpleSourceListView *)sourceList {
261 | self = [super init];
262 | if(!self)return nil;
263 |
264 | NSTextField *headerTextField = sourceList.textFieldForHeaders;
265 | self.textField = headerTextField;
266 | [self addSubview:headerTextField];
267 |
268 | NSImageView *itemImage = [[NSImageView alloc] init];
269 | self.imageView = itemImage;
270 | [self addSubview:itemImage];
271 |
272 | self.textField.stringValue = [title uppercaseString];
273 | return self;
274 | }
275 |
276 | - (void)setFrame:(NSRect)frameRect {
277 | [super setFrame:frameRect];
278 |
279 | self.textField.frame = CGRectMake(ORCellTitleLeftPadding, -ORCellItemTopPadding, CGRectGetWidth(frameRect) - ORCellItemLeftPadding, ORCellHeight);
280 | self.imageView.frame = CGRectMake(ORCellLeftPadding, CGRectGetHeight(frameRect)/2 - ORCellImageDimensions/2, ORCellImageDimensions, ORCellImageDimensions);
281 | }
282 |
283 | - (void)drawRect:(NSRect)dirtyRect {
284 | if (self.allowsVibrancy) {
285 | [[NSColor colorWithCalibratedRed:0.162 green:0.137 blue:0.160 alpha:0.300] set];
286 | } else {
287 | [[NSColor colorWithCalibratedRed:0.264 green:0.229 blue:0.257 alpha:1.000] set];
288 | }
289 |
290 | NSRectFill(dirtyRect);
291 | }
292 |
293 | @end
294 |
295 | @implementation ORSourceListItemView {
296 |
297 | NSString *_thumbnail;
298 | NSString *_selectedThumbnail;
299 | NSString *_rightImageName;
300 | NSString *_rightImageActiveName;
301 | ORSimpleSourceListView *_sourceList;
302 | }
303 |
304 | - (id)initWithSourceListItem:(ORSourceListItem *)item sourceList:(ORSimpleSourceListView *)sourceList {
305 | self = [super init];
306 | if (!self)return nil;
307 |
308 | _thumbnail = item.thumbnail.copy;
309 | _selectedThumbnail = item.selectedThumbnail.copy;
310 | _rightImageName = item.rightButtonImage.copy;
311 | _rightImageActiveName = item.rightButtonActiveImage.copy;
312 | _sourceList = sourceList;
313 |
314 | ORSimpleTextField *titleTextField = [sourceList textFieldForItems];
315 | titleTextField.lineBreakMode = NSLineBreakByTruncatingTail;
316 | self.textField = titleTextField;
317 | [self addSubview:titleTextField];
318 |
319 | self.textField.stringValue = item. title;
320 | self.textField.drawsBackground = NO;
321 |
322 | return self;
323 | }
324 |
325 | - (void)setFrame:(NSRect)frameRect {
326 | [super setFrame:frameRect];
327 |
328 | self.textField.frame = CGRectMake(ORCellItemLeftPadding, -ORCellItemTopPadding, CGRectGetWidth(frameRect) - ORCellItemLeftPadding, ORCellHeight);
329 | self.imageView.frame = CGRectMake(0, CGRectGetHeight(frameRect)/2 - ORCellImageDimensions/2, ORCellImageDimensions, ORCellImageDimensions);
330 | }
331 |
332 | @end
333 |
334 | @implementation ORSourceListRowView
335 |
336 | - (void)setSelected:(BOOL)selected
337 | {
338 | [super setSelected:selected];
339 |
340 | NSColor *color = selected ? [NSColor selectedMenuItemColor] : [ NSColor clearColor];
341 |
342 | for (NSView *view in self.subviews) {
343 | view.layer.backgroundColor = color.CGColor;
344 | }
345 | self.backgroundColor = color;
346 |
347 | }
348 |
349 | @end
--------------------------------------------------------------------------------
/objc/GIFs/ORSourcesController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORSourcesController.h
3 | // GIFs
4 | //
5 | // Created by Orta on 14/11/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ORMenuController.h"
11 |
12 | @interface ORSourcesController : NSObject
13 |
14 | @property (nonatomic, weak) IBOutlet ORMenuController *menuController;
15 | @property (nonatomic, weak) IBOutlet NSPopover *sourcePopover;
16 |
17 | @property (weak) IBOutlet NSTextField *tumblrURLTextField;
18 | @property (weak) IBOutlet NSButton *tumblrSaveButton;
19 |
20 | - (IBAction)tumblrTextfieldChanged:(NSTextField *)sender;
21 | - (IBAction)tumblrSavedTapped:(id)sender;
22 |
23 |
24 | @property (weak) IBOutlet NSTextField *redditTextField;
25 | @property (weak) IBOutlet NSButton *redditSaveButton;
26 |
27 | - (IBAction)redditTextFieldChanged:(NSTextField *)sender;
28 |
29 | - (IBAction)redditSaveTapped:(id)sender;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/objc/GIFs/ORSourcesController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORSourcesController.m
3 | // GIFs
4 | //
5 | // Created by Orta on 14/11/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORSourcesController.h"
10 | #import
11 |
12 | @implementation ORSourcesController
13 |
14 | - (IBAction)tumblrTextfieldChanged:(NSTextField *)sender {
15 |
16 | NSString *path = [NSString stringWithFormat:@"%@/api/read/json", sender.stringValue];
17 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:path]];
18 |
19 | AFHTTPRequestOperation *requestOp = [[AFHTTPRequestOperation alloc] initWithRequest:request];
20 | [requestOp setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
21 | self.tumblrSaveButton.image = [NSImage imageNamed:@"tick_active"];
22 |
23 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
24 | self.tumblrSaveButton.image = [NSImage imageNamed:@"tick"];
25 |
26 | }];
27 | [requestOp start];
28 | }
29 |
30 | - (IBAction)tumblrSavedTapped:(id)sender {
31 | [self.menuController addNewTumblr:self.tumblrURLTextField.stringValue];
32 | [self.sourcePopover performClose:self];
33 | }
34 |
35 | - (IBAction)redditTextFieldChanged:(NSTextField *)sender
36 | {
37 | NSString *path = [NSString stringWithFormat:@"http://www.reddit.com%@.json", sender.stringValue];
38 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:path]];
39 | AFHTTPRequestOperation *requestOp = [[AFHTTPRequestOperation alloc] initWithRequest:request];
40 | [requestOp setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
41 | self.redditSaveButton.image = [NSImage imageNamed:@"tick_active"];
42 |
43 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
44 | self.redditSaveButton.image = [NSImage imageNamed:@"tick"];
45 | }];
46 | [requestOp start];
47 | }
48 |
49 | - (IBAction)redditSaveTapped:(id)sender
50 | {
51 | [self.menuController addNewSubreddit:self.redditTextField.stringValue];
52 | [self.sourcePopover performClose:self];
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/objc/GIFs/ORStarredSourceController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORStarredSourceController.h
3 | // GIFs
4 | //
5 | // Created by Orta on 21/11/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ORGIFController.h"
11 |
12 | @class GIF;
13 |
14 | @interface ORStarredSourceController : NSObject
15 |
16 | @property (weak) IBOutlet ORGIFController *gifController;
17 |
18 | - (void)reloadData;
19 | - (BOOL)hasGIFWithDownloadAddress:(NSString *)address;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/objc/GIFs/ORStarredSourceController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORStarredSourceController.m
3 | // GIFs
4 | //
5 | // Created by Orta on 21/11/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORStarredSourceController.h"
10 | #import
11 |
12 |
13 | @implementation ORStarredSourceController {
14 | NSArray *_starred;
15 | }
16 |
17 | - (void)awakeFromNib {
18 | [self reloadData];
19 | }
20 |
21 | - (void)reloadData
22 | {
23 | NSString *path = [[NSFileManager defaultManager] pathForPrivateFile:@"starred.data"];
24 | NSSet *data = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
25 | if (data) {
26 | NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateAdded" ascending:NO];
27 | _starred = [data sortedArrayUsingDescriptors:@[descriptor]];
28 | }
29 | }
30 |
31 | - (void)getNextGIFs:(void (^)(NSArray *, NSError *))completion {
32 |
33 | }
34 |
35 |
36 | - (NSInteger)numberOfGifs {
37 | return _starred.count;
38 | }
39 |
40 | - (GIF *)gifAtIndex:(NSInteger)index {
41 | return _starred[index];
42 | }
43 |
44 | - (BOOL)hasGIFWithDownloadAddress:(NSString *)address
45 | {
46 | for (GIF *gif in _starred) {
47 | if ([gif.imageUID isEqualToString:address]) {
48 | return YES;
49 | }
50 | }
51 | return NO;
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/objc/GIFs/ORTintedVisualEffectView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ORTintedVisualEffectView.swift
3 | // GIFs
4 | //
5 | // Created by Orta on 8/5/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class ORTintedView: NSView {
12 |
13 | override func drawRect(dirtyRect: NSRect) {
14 | super.drawRect(dirtyRect)
15 | NSColor(calibratedRed: 0.162, green: 0.137, blue: 0.160, alpha: 0.75).set();
16 | NSRectFill(dirtyRect);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/objc/GIFs/ORTumblrController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORTumblrController.h
3 | // GIFs
4 | //
5 | // Created by orta therox on 21/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORGIFController.h"
10 |
11 | @interface ORTumblrController : NSObject
12 | - (void)setTumblrURL:(NSString *)tumblrURL;
13 | @end
14 |
--------------------------------------------------------------------------------
/objc/GIFs/ORTumblrController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORTumblrController.m
3 | // GIFs
4 | //
5 | // Created by orta therox on 21/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORTumblrController.h"
10 | #import "AFNetworking.h"
11 | #import "ORAppDelegate.h"
12 | #import
13 |
14 | @interface TumblrGIF : GIF
15 | @property (copy, nonatomic, readwrite) NSString *representedURL;
16 | @property (copy, nonatomic, readwrite) NSString *tumblrID;
17 |
18 | @property (assign, nonatomic, readwrite) NSInteger suffixIndex;
19 | @property (assign, nonatomic, readwrite) BOOL isTumblr;
20 | @end
21 |
22 | @implementation TumblrGIF
23 |
24 | + (NSArray *)suffixes
25 | {
26 | return @[@"75sq", @"100", @"250", @"300", @"400", @"500"];
27 | }
28 |
29 | - (void)setRepresentedURL:(NSString *)representedURL
30 | {
31 | self.isTumblr = NO;
32 |
33 | for (NSString *size in self.class.suffixes ) {
34 | NSString *remove = [NSString stringWithFormat:@"_%@.gif", size];
35 |
36 | if ([representedURL containsString:remove]) {
37 | self.suffixIndex = [self.class.suffixes indexOfObject:size];
38 | self.isTumblr = YES;
39 | }
40 | representedURL = [representedURL stringByReplacingOccurrencesOfString:remove withString:@""];
41 | }
42 |
43 | if (self.isTumblr) {
44 | self.tumblrID = [[representedURL componentsSeparatedByString:@"tumblr.com"] lastObject];
45 | }
46 | _representedURL = representedURL;
47 | }
48 |
49 | - (id) imageRepresentation
50 | {
51 | return self.downloadURL;
52 | }
53 |
54 | - (NSURL *)downloadURL
55 | {
56 | if (!self.representedURL) return nil;
57 |
58 | if (self.isTumblr) {
59 | NSString *fullURL = [NSString stringWithFormat:@"%@_%@.gif",self.representedURL, self.class.suffixes[self.suffixIndex]];
60 | return [NSURL URLWithString:fullURL];
61 | } else {
62 | return [super downloadURL];
63 | }
64 | }
65 |
66 | - (NSUInteger)hash
67 | {
68 | if (self.isTumblr) {
69 | return self.tumblrID.hash;
70 | } else {
71 | return self.representedURL.hash;
72 | }
73 | }
74 |
75 | - (BOOL)isEqual:(id)object
76 | {
77 | if ([object isKindOfClass:self.class]) {
78 | if (self.isTumblr) {
79 | return [self.tumblrID isEqual:[object tumblrID]];
80 | } else {
81 | return [self.representedURL isEqual:[object representedURL]];
82 | }
83 |
84 | }
85 | return [super isEqual:object];
86 | }
87 |
88 | @end
89 |
90 | @implementation ORTumblrController {
91 | NSString *_url;
92 | NSArray *_gifs;
93 |
94 | NSInteger _offset;
95 | BOOL _downloading;
96 | }
97 |
98 | - (void)setTumblrURL:(NSString *)tumblrURL {
99 |
100 | _url = tumblrURL;
101 | _gifs = @[];
102 | _offset = 0;
103 | _downloading = NO;
104 | }
105 |
106 | - (void)getNextGIFs:(void (^)(NSArray *newGIFs, NSError *error))completion;
107 | {
108 | if (_downloading) return;
109 |
110 | // http://whatshouldwecallme.tumblr.com/api/read/json
111 |
112 | NSString *address = [_url stringByAppendingFormat:@"/api/read/json?start=%@", @(_offset)];
113 |
114 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
115 | AFHTTPRequestOperation *op = [manager GET:address parameters:nil success:^(AFHTTPRequestOperation *operation, id JSON) {
116 |
117 | [ORAppDelegate setNetworkActivity:NO];
118 | _offset += 25;
119 |
120 | NSError *error = nil;
121 | NSString *string = [operation.responseString stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
122 | NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
123 | NSMutableSet *newGIFs = [NSMutableSet set];
124 |
125 | [linkDetector enumerateMatchesInString:string
126 | options:0
127 | range:NSMakeRange(0, [string length])
128 | usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
129 | if ([match resultType] == NSTextCheckingTypeLink) {
130 | NSURL *url = [match URL];
131 |
132 | if ([url.absoluteString rangeOfString:@".gif"].location != NSNotFound) {
133 | NSString *address = [url.absoluteString stringByReplacingOccurrencesOfString:@"%5C" withString:@""];
134 | TumblrGIF *gif = [[TumblrGIF alloc] initWithDownloadURL:address thumbnail:address source:_url sourceTitle:_url ];
135 | gif.representedURL = address;
136 | if (gif) {
137 | if ([newGIFs containsObject:gif]) {
138 |
139 | // Set the suffix index to be the highest of the two
140 |
141 | for (TumblrGIF *searchGIF in newGIFs) {
142 | if ([searchGIF.representedURL isEqualToString:gif.representedURL]) {
143 | searchGIF.suffixIndex = MAX(searchGIF.suffixIndex, gif.suffixIndex);
144 | }
145 | }
146 | } else {
147 | [newGIFs addObject:gif];
148 | }
149 |
150 | }
151 | }
152 | }
153 | }];
154 |
155 | _gifs = [_gifs arrayByAddingObjectsFromArray:newGIFs.allObjects];
156 | _downloading = NO;
157 | if (completion) completion(newGIFs.allObjects, nil);
158 |
159 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
160 | if (completion) completion(nil, error);
161 | }];
162 | op.responseSerializer = [[AFHTTPResponseSerializer alloc] init];
163 |
164 | _downloading = YES;
165 | [ORAppDelegate setNetworkActivity:YES];
166 | }
167 |
168 | - (NSInteger)numberOfGifs {
169 | return _gifs.count;
170 | }
171 |
172 | - (GIF *)gifAtIndex:(NSInteger)index {
173 | return _gifs[index];
174 | }
175 |
176 | @end
177 |
--------------------------------------------------------------------------------
/objc/GIFs/ORWebViewDelegateStuff.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORWebViewDelegateStuff.h
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class ORGIFController;
13 | @interface ORWebViewDelegateStuff : NSObject
14 | @property (weak) IBOutlet WebView *webView;
15 | @property (weak) IBOutlet ORGIFController *gifController;
16 | @end
17 |
--------------------------------------------------------------------------------
/objc/GIFs/ORWebViewDelegateStuff.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORWebViewDelegateStuff.m
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORWebViewDelegateStuff.h"
10 | #import "ORGIFRightClickMenuMaker.h"
11 | #import "ORGIFController.h"
12 |
13 | @implementation ORWebViewDelegateStuff {
14 | NSURL *currentAddress;
15 | ORGIFRightClickMenuMaker *menuMaker;
16 | }
17 |
18 | - (void)awakeFromNib {
19 | _webView.UIDelegate = self;
20 | }
21 |
22 | - (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems {
23 |
24 | NSMenuItem *copy = nil;
25 | for (NSMenuItem *item in defaultMenuItems) {
26 | // I want Copy Image, but I can't look at title due to localisation stuff
27 | if (item.tag == 6) {
28 | copy = item;
29 | }
30 | }
31 |
32 | GIF *gif = self.gifController.currentGIF;
33 | if (gif) {
34 | menuMaker = [[ORGIFRightClickMenuMaker alloc] initWithGIF:gif];
35 | return [menuMaker menuItemsWithImageCopyItem:copy];
36 | }
37 | return @[];
38 | }
39 |
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/objc/GIFs/ORWindowDraggableVisualEffectsView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ORWindowDraggableVisualEffectsView.h
3 | // GIFs
4 | //
5 | // Created by Orta on 8/20/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ORWindowDraggableVisualEffectsView : NSVisualEffectView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/objc/GIFs/ORWindowDraggableVisualEffectsView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ORWindowDraggableVisualEffectsView.m
3 | // GIFs
4 | //
5 | // Created by Orta on 8/20/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import "ORWindowDraggableVisualEffectsView.h"
10 |
11 | @interface ORWindowDraggableVisualEffectsView()
12 | @property (assign) NSPoint initialLocation;
13 | @end
14 |
15 | @implementation ORWindowDraggableVisualEffectsView
16 |
17 | - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
18 | {
19 | return YES;
20 | }
21 |
22 | - (void)mouseDown:(NSEvent *)theEvent
23 | {
24 | self.initialLocation = [theEvent locationInWindow];
25 | }
26 |
27 | - (void)mouseDragged:(NSEvent *)theEvent
28 | {
29 |
30 | NSRect screenVisibleFrame = [self.window.screen visibleFrame];
31 | NSRect windowFrame = [self.window frame];
32 | NSPoint newOrigin = windowFrame.origin;
33 |
34 | // Get the mouse location in window coordinates.
35 | NSPoint currentLocation = [theEvent locationInWindow];
36 | // Update the origin with the difference between the new mouse location and the old mouse location.
37 | newOrigin.x += (currentLocation.x - self.initialLocation.x);
38 | newOrigin.y += (currentLocation.y - self.initialLocation.y);
39 |
40 | // Don't let window get dragged up under the menu bar
41 | if ((newOrigin.y + windowFrame.size.height) > (screenVisibleFrame.origin.y + screenVisibleFrame.size.height)) {
42 | newOrigin.y = screenVisibleFrame.origin.y + (screenVisibleFrame.size.height - windowFrame.size.height);
43 | }
44 |
45 | // Move the window to the new location
46 | [self.window setFrameOrigin:newOrigin];
47 | }
48 |
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/objc/GIFs/ORWindowTitleDecorationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ORWindowTitleDecorationController.swift
3 | // GIFs
4 | //
5 | // Created by Orta on 8/7/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import AppKit
11 |
12 | @objc public class ORWindowTitleDecorationController: NSObject, NSSplitViewDelegate {
13 |
14 | @IBOutlet weak var mainWindow: NSWindow!
15 | @IBOutlet weak var titleBlurView: NSView!
16 | @IBOutlet weak var sourceListSuperView: NSView!
17 | @IBOutlet weak var fakeRightSplitter: NSView!
18 | @IBOutlet weak var rightColumnView: NSView!
19 |
20 | @IBOutlet weak var itemTitle: NSTextField!
21 | @IBOutlet weak var sectionTitle: NSTextField!
22 |
23 | @IBOutlet weak var gridAndDetailSplitter: NSSplitView!
24 |
25 | @IBOutlet weak var giphyLogo: NSImageView!
26 |
27 | @objc public func showGiphyLogo(show:ObjCBool) {
28 | giphyLogo.hidden = !show.boolValue
29 | }
30 |
31 | override public func awakeFromNib() {
32 | guard let content = mainWindow.contentView else { return }
33 | content.addSubview(self.titleBlurView);
34 |
35 | NSNotificationCenter.defaultCenter().addObserver(self, selector: "updateToolbarBlur", name: NSWindowDidResizeNotification, object: self.mainWindow)
36 | updateToolbarBlur()
37 |
38 | giphyLogo.animates = true
39 |
40 | var path = NSBundle.mainBundle().pathForResource("Giphy_API_Logo_ForWhite_Trans", ofType: "gif")!
41 | giphyLogo.image = NSImage(contentsOfFile: path)
42 |
43 | }
44 |
45 | public func splitView(splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
46 | return (splitView == self.fakeRightSplitter && dividerIndex == 0) ? 180 : proposedMinimumPosition;
47 | }
48 |
49 | public func splitView(splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
50 | return (splitView == self.fakeRightSplitter && dividerIndex == 0) ? 240 : proposedMaximumPosition;
51 | }
52 |
53 | public func splitView(splitView: NSSplitView, constrainSplitPosition proposedPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
54 | self.updateToolbarBlur();
55 | return proposedPosition;
56 | }
57 |
58 | func updateToolbarBlur(){
59 | let windowFrame = self.titleBlurView.window?.frame
60 | let leftColumnWidth = CGRectGetWidth(self.sourceListSuperView.frame)
61 | let titleWidth = CGRectGetWidth(windowFrame!) - leftColumnWidth
62 | let titleHeight = CGRectGetHeight(self.titleBlurView.bounds)
63 | let rightColumnWidth = CGRectGetWidth(self.rightColumnView.frame)
64 |
65 | self.titleBlurView.frame = CGRectMake(leftColumnWidth, CGRectGetHeight(windowFrame!) - titleHeight + 1, titleWidth , titleHeight);
66 |
67 | self.fakeRightSplitter.frame = CGRectMake(titleWidth - rightColumnWidth, 0, 1, titleHeight)
68 |
69 | self.itemTitle.frame = CGRectMake(titleWidth - rightColumnWidth + 2, 18, rightColumnWidth , 18);
70 |
71 | self.sectionTitle.frame = CGRectMake(0, 18, titleWidth - rightColumnWidth, 18);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/objc/GIFs/Reddit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/Reddit.png
--------------------------------------------------------------------------------
/objc/GIFs/Reddit@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/Reddit@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/RedditWhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/RedditWhite.png
--------------------------------------------------------------------------------
/objc/GIFs/RedditWhite@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/RedditWhite@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/SBSystemPreferences.h:
--------------------------------------------------------------------------------
1 | /*
2 | * SBSystemPreferences.h
3 | */
4 |
5 | #import
6 | #import
7 |
8 |
9 | @class SBSystemPreferencesItem, SBSystemPreferencesApplication, SBSystemPreferencesColor, SBSystemPreferencesDocument, SBSystemPreferencesWindow, SBSystemPreferencesAttributeRun, SBSystemPreferencesCharacter, SBSystemPreferencesParagraph, SBSystemPreferencesText, SBSystemPreferencesAttachment, SBSystemPreferencesWord, SBSystemPreferencesAnchor, SBSystemPreferencesPane, SBSystemPreferencesPrintSettings;
10 |
11 | enum SBSystemPreferencesSavo {
12 | SBSystemPreferencesSavoAsk = 'ask ' /* Ask the user whether or not to save the file. */,
13 | SBSystemPreferencesSavoNo = 'no ' /* Do not save the file. */,
14 | SBSystemPreferencesSavoYes = 'yes ' /* Save the file. */
15 | };
16 | typedef enum SBSystemPreferencesSavo SBSystemPreferencesSavo;
17 |
18 | enum SBSystemPreferencesEnum {
19 | SBSystemPreferencesEnumStandard = 'lwst' /* Standard PostScript error handling */,
20 | SBSystemPreferencesEnumDetailed = 'lwdt' /* print a detailed report of PostScript errors */
21 | };
22 | typedef enum SBSystemPreferencesEnum SBSystemPreferencesEnum;
23 |
24 |
25 |
26 | /*
27 | * Standard Suite
28 | */
29 |
30 | // A scriptable object.
31 | @interface SBSystemPreferencesItem : SBObject
32 |
33 | @property (copy) NSDictionary *properties; // All of the object's properties.
34 |
35 | - (void) closeSaving:(SBSystemPreferencesSavo)saving savingIn:(NSURL *)savingIn; // Close an object.
36 | - (void) delete; // Delete an object.
37 | - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location.
38 | - (BOOL) exists; // Verify if an object exists.
39 | - (void) moveTo:(SBObject *)to; // Move object(s) to a new location.
40 | - (void) saveAs:(NSString *)as in:(NSURL *)in_; // Save an object.
41 |
42 | @end
43 |
44 | // An application's top level scripting object.
45 | @interface SBSystemPreferencesApplication : SBApplication
46 |
47 | - (SBElementArray *) documents;
48 | - (SBElementArray *) windows;
49 |
50 | @property (readonly) BOOL frontmost; // Is this the frontmost (active) application?
51 | @property (copy, readonly) NSString *name; // The name of the application.
52 | @property (copy, readonly) NSString *version; // The version of the application.
53 |
54 | - (SBSystemPreferencesDocument *) open:(NSURL *)x; // Open an object.
55 | - (void) print:(NSURL *)x printDialog:(BOOL)printDialog withProperties:(SBSystemPreferencesPrintSettings *)withProperties; // Print an object.
56 | - (void) quitSaving:(SBSystemPreferencesSavo)saving; // Quit an application.
57 |
58 | @end
59 |
60 | // A color.
61 | @interface SBSystemPreferencesColor : SBSystemPreferencesItem
62 |
63 |
64 | @end
65 |
66 | // A document.
67 | @interface SBSystemPreferencesDocument : SBSystemPreferencesItem
68 |
69 | @property (readonly) BOOL modified; // Has the document been modified since the last save?
70 | @property (copy) NSString *name; // The document's name.
71 | @property (copy) NSString *path; // The document's path.
72 |
73 |
74 | @end
75 |
76 | // A window.
77 | @interface SBSystemPreferencesWindow : SBSystemPreferencesItem
78 |
79 | @property NSRect bounds; // The bounding rectangle of the window.
80 | @property (readonly) BOOL closeable; // Whether the window has a close box.
81 | @property (copy, readonly) SBSystemPreferencesDocument *document; // The document whose contents are being displayed in the window.
82 | @property (readonly) BOOL floating; // Whether the window floats.
83 | - (NSInteger) id; // The unique identifier of the window.
84 | @property NSInteger index; // The index of the window, ordered front to back.
85 | @property (readonly) BOOL miniaturizable; // Whether the window can be miniaturized.
86 | @property BOOL miniaturized; // Whether the window is currently miniaturized.
87 | @property (readonly) BOOL modal; // Whether the window is the application's current modal window.
88 | @property (copy) NSString *name; // The full title of the window.
89 | @property (readonly) BOOL resizable; // Whether the window can be resized.
90 | @property (readonly) BOOL titled; // Whether the window has a title bar.
91 | @property BOOL visible; // Whether the window is currently visible.
92 | @property (readonly) BOOL zoomable; // Whether the window can be zoomed.
93 | @property BOOL zoomed; // Whether the window is currently zoomed.
94 |
95 |
96 | @end
97 |
98 |
99 |
100 | /*
101 | * Text Suite
102 | */
103 |
104 | // This subdivides the text into chunks that all have the same attributes.
105 | @interface SBSystemPreferencesAttributeRun : SBSystemPreferencesItem
106 |
107 | - (SBElementArray *) attachments;
108 | - (SBElementArray *) attributeRuns;
109 | - (SBElementArray *) characters;
110 | - (SBElementArray *) paragraphs;
111 | - (SBElementArray *) words;
112 |
113 | @property (copy) NSColor *color; // The color of the first character.
114 | @property (copy) NSString *font; // The name of the font of the first character.
115 | @property NSInteger size; // The size in points of the first character.
116 |
117 |
118 | @end
119 |
120 | // This subdivides the text into characters.
121 | @interface SBSystemPreferencesCharacter : SBSystemPreferencesItem
122 |
123 | - (SBElementArray *) attachments;
124 | - (SBElementArray *) attributeRuns;
125 | - (SBElementArray *) characters;
126 | - (SBElementArray *) paragraphs;
127 | - (SBElementArray *) words;
128 |
129 | @property (copy) NSColor *color; // The color of the first character.
130 | @property (copy) NSString *font; // The name of the font of the first character.
131 | @property NSInteger size; // The size in points of the first character.
132 |
133 |
134 | @end
135 |
136 | // This subdivides the text into paragraphs.
137 | @interface SBSystemPreferencesParagraph : SBSystemPreferencesItem
138 |
139 | - (SBElementArray *) attachments;
140 | - (SBElementArray *) attributeRuns;
141 | - (SBElementArray *) characters;
142 | - (SBElementArray *) paragraphs;
143 | - (SBElementArray *) words;
144 |
145 | @property (copy) NSColor *color; // The color of the first character.
146 | @property (copy) NSString *font; // The name of the font of the first character.
147 | @property NSInteger size; // The size in points of the first character.
148 |
149 |
150 | @end
151 |
152 | // Rich (styled) text
153 | @interface SBSystemPreferencesText : SBSystemPreferencesItem
154 |
155 | - (SBElementArray *) attachments;
156 | - (SBElementArray *) attributeRuns;
157 | - (SBElementArray *) characters;
158 | - (SBElementArray *) paragraphs;
159 | - (SBElementArray *) words;
160 |
161 | @property (copy) NSColor *color; // The color of the first character.
162 | @property (copy) NSString *font; // The name of the font of the first character.
163 | @property NSInteger size; // The size in points of the first character.
164 |
165 |
166 | @end
167 |
168 | // Represents an inline text attachment. This class is used mainly for make commands.
169 | @interface SBSystemPreferencesAttachment : SBSystemPreferencesText
170 |
171 | @property (copy) NSString *fileName; // The path to the file for the attachment
172 |
173 |
174 | @end
175 |
176 | // This subdivides the text into words.
177 | @interface SBSystemPreferencesWord : SBSystemPreferencesItem
178 |
179 | - (SBElementArray *) attachments;
180 | - (SBElementArray *) attributeRuns;
181 | - (SBElementArray *) characters;
182 | - (SBElementArray *) paragraphs;
183 | - (SBElementArray *) words;
184 |
185 | @property (copy) NSColor *color; // The color of the first character.
186 | @property (copy) NSString *font; // The name of the font of the first character.
187 | @property NSInteger size; // The size in points of the first character.
188 |
189 |
190 | @end
191 |
192 |
193 |
194 | /*
195 | * System Preferences
196 | */
197 |
198 | // an anchor within a preference pane
199 | @interface SBSystemPreferencesAnchor : SBSystemPreferencesItem
200 |
201 | @property (copy, readonly) NSString *name; // name of the anchor within a preference pane
202 |
203 | - (SBSystemPreferencesAnchor *) reveal; // Reveals an anchor within a preference pane or preference pane itself
204 |
205 | @end
206 |
207 | // System Preferences top level scripting object
208 | @interface SBSystemPreferencesApplication (SystemPreferences)
209 |
210 | - (SBElementArray *) panes;
211 |
212 | @property (copy) SBSystemPreferencesPane *currentPane; // the currently selected pane
213 | @property (copy, readonly) SBSystemPreferencesWindow *preferencesWindow; // the main preferences window
214 | @property BOOL showAll; // Is SystemPrefs in show all view. (Setting to false will do nothing)
215 |
216 | @end
217 |
218 | // a preference pane
219 | @interface SBSystemPreferencesPane : SBSystemPreferencesItem
220 |
221 | - (SBElementArray *) anchors;
222 |
223 | - (NSString *) id; // locale independent name of the preference pane; can refer to a pane using the expression: pane id ""
224 | @property (copy, readonly) NSString *localizedName; // localized name of the preference pane
225 | @property (copy, readonly) NSString *name; // name of the preference pane as it appears in the title bar; can refer to a pane using the expression: pane ""
226 |
227 | - (double) timedLoad; // Times and loads given preference pane and returns load time.
228 |
229 | @end
230 |
231 |
232 |
233 | /*
234 | * Type Definitions
235 | */
236 |
237 | @interface SBSystemPreferencesPrintSettings : SBObject
238 |
239 | @property NSInteger copies; // the number of copies of a document to be printed
240 | @property BOOL collating; // Should printed copies be collated?
241 | @property NSInteger startingPage; // the first page of the document to be printed
242 | @property NSInteger endingPage; // the last page of the document to be printed
243 | @property NSInteger pagesAcross; // number of logical pages laid across a physical page
244 | @property NSInteger pagesDown; // number of logical pages laid out down a physical page
245 | @property (copy) NSDate *requestedPrintTime; // the time at which the desktop printer should print the document
246 | @property SBSystemPreferencesEnum errorHandling; // how errors are handled
247 | @property (copy) NSString *faxNumber; // for fax number
248 | @property (copy) NSString *targetPrinter; // for target printer
249 |
250 | - (void) closeSaving:(SBSystemPreferencesSavo)saving savingIn:(NSURL *)savingIn; // Close an object.
251 | - (void) delete; // Delete an object.
252 | - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location.
253 | - (BOOL) exists; // Verify if an object exists.
254 | - (void) moveTo:(SBObject *)to; // Move object(s) to a new location.
255 | - (void) saveAs:(NSString *)as in:(NSURL *)in_; // Save an object.
256 |
257 | @end
258 |
259 |
--------------------------------------------------------------------------------
/objc/GIFs/Search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/Search.png
--------------------------------------------------------------------------------
/objc/GIFs/Search@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/Search@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/SearchWhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/SearchWhite.png
--------------------------------------------------------------------------------
/objc/GIFs/SearchWhite@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/SearchWhite@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/ShadowView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShadowView.swift
3 | // GIFs
4 | //
5 | // Created by Orta on 8/7/14.
6 | // Copyright (c) 2014 Orta Therox. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class ShadowView: NSView {
12 | override func drawRect(dirtyRect: NSRect) {
13 | super.drawRect(dirtyRect)
14 | NSColor(patternImage: NSImage(named: "shadow")!).set();
15 | NSRectFill(dirtyRect);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/objc/GIFs/TwitterBird.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/TwitterBird.png
--------------------------------------------------------------------------------
/objc/GIFs/about0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about0.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about1.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about10.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about11.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about12.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about13.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about14.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about2.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about3.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about4.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about5.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about6.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about7.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about8.jpg
--------------------------------------------------------------------------------
/objc/GIFs/about9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/about9.jpg
--------------------------------------------------------------------------------
/objc/GIFs/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/close.png
--------------------------------------------------------------------------------
/objc/GIFs/close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/close@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/close_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/close_active.png
--------------------------------------------------------------------------------
/objc/GIFs/close_active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/close_active@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/en.lproj/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
2 | {\colortbl;\red255\green255\blue255;}
3 | \paperw9840\paperh8400
4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
5 |
6 | \f0\b\fs24 \cf0 Engineering:
7 | \b0 \
8 | Some people\
9 | \
10 |
11 | \b Human Interface Design:
12 | \b0 \
13 | Some other people\
14 | \
15 |
16 | \b Testing:
17 | \b0 \
18 | Hopefully not nobody\
19 | \
20 |
21 | \b Documentation:
22 | \b0 \
23 | Whoever\
24 | \
25 |
26 | \b With special thanks to:
27 | \b0 \
28 | Mom\
29 | }
30 |
--------------------------------------------------------------------------------
/objc/GIFs/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/objc/GIFs/gif_template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
72 |
73 |
74 |
75 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/objc/GIFs/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // GIFs
4 | //
5 | // Created by orta therox on 12/01/2013.
6 | // Copyright (c) 2013 Orta Therox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | return NSApplicationMain(argc, (const char **)argv);
14 | }
15 |
--------------------------------------------------------------------------------
/objc/GIFs/more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/more.png
--------------------------------------------------------------------------------
/objc/GIFs/plus_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/plus_active.png
--------------------------------------------------------------------------------
/objc/GIFs/plus_active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/plus_active@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/plus_active@2x.pxm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/plus_active@2x.pxm
--------------------------------------------------------------------------------
/objc/GIFs/shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/shadow.png
--------------------------------------------------------------------------------
/objc/GIFs/tick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tick.png
--------------------------------------------------------------------------------
/objc/GIFs/tick@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tick@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/tick_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tick_active.png
--------------------------------------------------------------------------------
/objc/GIFs/tick_active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tick_active@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/tumblr_t.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tumblr_t.png
--------------------------------------------------------------------------------
/objc/GIFs/tumblr_t@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tumblr_t@2x.png
--------------------------------------------------------------------------------
/objc/GIFs/tumblr_t_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tumblr_t_active.png
--------------------------------------------------------------------------------
/objc/GIFs/tumblr_t_active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/objc/GIFs/tumblr_t_active@2x.png
--------------------------------------------------------------------------------
/objc/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem "cocoapods", "1.1.0.rc.2"
4 | gem "cocoapods-keys"
5 | gem "cocoapods-deintegrate"
6 |
--------------------------------------------------------------------------------
/objc/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | RubyInline (3.12.4)
5 | ZenTest (~> 4.3)
6 | ZenTest (4.11.1)
7 | activesupport (4.2.7.1)
8 | i18n (~> 0.7)
9 | json (~> 1.7, >= 1.7.7)
10 | minitest (~> 5.1)
11 | thread_safe (~> 0.3, >= 0.3.4)
12 | tzinfo (~> 1.1)
13 | claide (1.0.0)
14 | cocoapods (1.1.0.rc.2)
15 | activesupport (>= 4.0.2, < 5)
16 | claide (>= 1.0.0, < 2.0)
17 | cocoapods-core (= 1.1.0.rc.2)
18 | cocoapods-deintegrate (>= 1.0.1, < 2.0)
19 | cocoapods-downloader (>= 1.1.1, < 2.0)
20 | cocoapods-plugins (>= 1.0.0, < 2.0)
21 | cocoapods-search (>= 1.0.0, < 2.0)
22 | cocoapods-stats (>= 1.0.0, < 2.0)
23 | cocoapods-trunk (>= 1.0.0, < 2.0)
24 | cocoapods-try (>= 1.1.0, < 2.0)
25 | colored (~> 1.2)
26 | escape (~> 0.0.4)
27 | fourflusher (~> 1.0.1)
28 | gh_inspector (~> 1.0)
29 | molinillo (~> 0.5.1)
30 | nap (~> 1.0)
31 | xcodeproj (>= 1.3.1, < 2.0)
32 | cocoapods-core (1.1.0.rc.2)
33 | activesupport (>= 4.0.2, < 5)
34 | fuzzy_match (~> 2.0.4)
35 | nap (~> 1.0)
36 | cocoapods-deintegrate (1.0.1)
37 | cocoapods-downloader (1.1.1)
38 | cocoapods-keys (1.7.0)
39 | dotenv
40 | osx_keychain
41 | cocoapods-plugins (1.0.0)
42 | nap
43 | cocoapods-search (1.0.0)
44 | cocoapods-stats (1.0.0)
45 | cocoapods-trunk (1.0.0)
46 | nap (>= 0.8, < 2.0)
47 | netrc (= 0.7.8)
48 | cocoapods-try (1.1.0)
49 | colored (1.2)
50 | dotenv (2.1.1)
51 | escape (0.0.4)
52 | fourflusher (1.0.1)
53 | fuzzy_match (2.0.4)
54 | gh_inspector (1.0.2)
55 | i18n (0.7.0)
56 | json (1.8.3)
57 | minitest (5.9.0)
58 | molinillo (0.5.1)
59 | nap (1.1.0)
60 | netrc (0.7.8)
61 | osx_keychain (1.0.1)
62 | RubyInline (~> 3)
63 | thread_safe (0.3.5)
64 | tzinfo (1.2.2)
65 | thread_safe (~> 0.1)
66 | xcodeproj (1.3.1)
67 | activesupport (>= 3)
68 | claide (>= 1.0.0, < 2.0)
69 | colored (~> 1.2)
70 |
71 | PLATFORMS
72 | ruby
73 |
74 | DEPENDENCIES
75 | cocoapods (= 1.1.0.rc.2)
76 | cocoapods-deintegrate
77 | cocoapods-keys
78 |
79 | BUNDLED WITH
80 | 1.12.5
81 |
--------------------------------------------------------------------------------
/objc/Makefile:
--------------------------------------------------------------------------------
1 | bootstrap:
2 | bundle install
3 | @echo "\nSetting up API Keys, leave blank if you don't know."
4 | @printf '\nWhat is your Giphy API Key ( use the one on https://github.com/Giphy/GiphyAPI if you do not have one )? '; \
5 | read GIPHY_API_KEY; \
6 |
7 | bundle exec pod keys set GiphyAPIKey "$$GIPHY_API_KEY" GIFs
8 | bundle exec pod keys set GiphyAPIKey "$$GIPHY_API_KEY" GIFs
9 | bundle exec pod keys set RandoTwitterBotConsumerKey "" GIFs
10 | bundle exec pod keys set RandoTwitterBotConsumerSecret "" GIFs
11 | bundle exec pod keys set RandoTwitterBotOAuthToken "" GIFs
12 | bundle exec pod keys set RandoTwitterBotOAuthTokenSecret "" GIFs
13 |
14 | bundle exec pod install
15 |
--------------------------------------------------------------------------------
/objc/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, "10.9"
2 |
3 | plugin 'cocoapods-keys', {
4 | :project => "GIFs",
5 | :keys => [
6 | "GiphyAPIKey",
7 | "RandoTwitterBotConsumerKey",
8 | "RandoTwitterBotConsumerSecret",
9 | "RandoTwitterBotOAuthToken",
10 | "RandoTwitterBotOAuthTokenSecret"
11 | ]
12 | }
13 |
14 | target "GIFs" do
15 | pod 'StandardPaths', '~> 1.5.4'
16 | pod "GIFKit", :git => "https://github.com/orta/GIFKit.git"
17 | pod 'STTwitter', '~> 0.2'
18 | end
--------------------------------------------------------------------------------
/objc/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AFNetworking (2.6.3):
3 | - AFNetworking/NSURLConnection (= 2.6.3)
4 | - AFNetworking/NSURLSession (= 2.6.3)
5 | - AFNetworking/Reachability (= 2.6.3)
6 | - AFNetworking/Security (= 2.6.3)
7 | - AFNetworking/Serialization (= 2.6.3)
8 | - AFNetworking/UIKit (= 2.6.3)
9 | - AFNetworking/NSURLConnection (2.6.3):
10 | - AFNetworking/Reachability
11 | - AFNetworking/Security
12 | - AFNetworking/Serialization
13 | - AFNetworking/NSURLSession (2.6.3):
14 | - AFNetworking/Reachability
15 | - AFNetworking/Security
16 | - AFNetworking/Serialization
17 | - AFNetworking/Reachability (2.6.3)
18 | - AFNetworking/Security (2.6.3)
19 | - AFNetworking/Serialization (2.6.3)
20 | - GIFKit (0.1.0):
21 | - AFNetworking (~> 2.3)
22 | - Keys (1.0.0)
23 | - StandardPaths (1.5.6)
24 | - STTwitter (0.2.5)
25 |
26 | DEPENDENCIES:
27 | - GIFKit (from `https://github.com/orta/GIFKit.git`)
28 | - Keys (from `Pods/CocoaPodsKeys`)
29 | - StandardPaths (~> 1.5.4)
30 | - STTwitter (~> 0.2)
31 |
32 | EXTERNAL SOURCES:
33 | GIFKit:
34 | :git: https://github.com/orta/GIFKit.git
35 | Keys:
36 | :path: Pods/CocoaPodsKeys
37 |
38 | CHECKOUT OPTIONS:
39 | GIFKit:
40 | :commit: f9b71bfce26cb61bbad3aa890c539699e924e9af
41 | :git: https://github.com/orta/GIFKit.git
42 |
43 | SPEC CHECKSUMS:
44 | AFNetworking: cb8d14a848e831097108418f5d49217339d4eb60
45 | GIFKit: 2588e9225ea99351a3525b2205605ab1b9307866
46 | Keys: 9c35bf00f612ee1d48556f4a4b9b4551e224e90f
47 | StandardPaths: 0c11c9256a68dd2339d4d2de647a5bd819648c46
48 | STTwitter: 5c157e8dcb4f0e4cf5b4374393021b7d7b7fd497
49 |
50 | PODFILE CHECKSUM: ef1686754bd76bb3917f80e90a403ab3227659e0
51 |
52 | COCOAPODS: 1.1.0.rc.2
53 |
--------------------------------------------------------------------------------
/web/GIFs.app.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/web/GIFs.app.zip
--------------------------------------------------------------------------------
/web/yosemite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/GIFs/de70a076ca6c695319b047f4cd002b6e162b61f9/web/yosemite.png
--------------------------------------------------------------------------------