trying to add images
This commit is contained in:
parent
555e7cca3c
commit
a128e0278d
17 changed files with 369 additions and 31 deletions
|
@ -13,6 +13,8 @@
|
||||||
#import "Constants.h"
|
#import "Constants.h"
|
||||||
#import "AccessToken.h"
|
#import "AccessToken.h"
|
||||||
#import <Growl/Growl.h>
|
#import <Growl/Growl.h>
|
||||||
|
#import "NSData+Base64.h"
|
||||||
|
#import "MimeType.h"
|
||||||
|
|
||||||
@interface Controller : NSObject <GrowlApplicationBridgeDelegate> {
|
@interface Controller : NSObject <GrowlApplicationBridgeDelegate> {
|
||||||
IBOutlet WebView *timelineView;
|
IBOutlet WebView *timelineView;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#import "Controller.h"
|
#import "Controller.h"
|
||||||
#import "NewMessageWindow.h"
|
#import "NewMessageWindow.h"
|
||||||
#import "PostModel.h"
|
#import "PostModel.h"
|
||||||
|
#import "NSData+Base64.h"
|
||||||
|
|
||||||
@implementation Controller
|
@implementation Controller
|
||||||
@synthesize loginViewWindow;
|
@synthesize loginViewWindow;
|
||||||
|
@ -244,7 +245,6 @@
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (IBAction)openNewMessageWindow:(id)sender
|
- (IBAction)openNewMessageWindow:(id)sender
|
||||||
{
|
{
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
@ -273,7 +273,6 @@
|
||||||
NewMessageWindow *newTweet = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil];
|
NewMessageWindow *newTweet = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil];
|
||||||
[newTweet withString:aString];
|
[newTweet withString:aString];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
|
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
|
||||||
|
@ -292,11 +291,24 @@
|
||||||
if (post.location) {
|
if (post.location) {
|
||||||
locationObject = [NSString stringWithFormat:@"[%f, %f]", post.location.coordinate.latitude, post.location.coordinate.longitude];
|
locationObject = [NSString stringWithFormat:@"[%f, %f]", post.location.coordinate.latitude, post.location.coordinate.longitude];
|
||||||
}
|
}
|
||||||
NSString *func = [NSString stringWithFormat:@"tentia_instance.sendNewMessage(\"%@\", \"%@\", \"%@\", %@)",
|
|
||||||
|
NSString *imageFilePath = @"null";
|
||||||
|
if (post.imageFilePath) {
|
||||||
|
NSError *error;
|
||||||
|
NSString *mimeType = [MimeType mimeTypeForFileAtPath:post.imageFilePath error:&error];
|
||||||
|
NSData *data = [[NSData alloc] initWithContentsOfFile:post.imageFilePath];
|
||||||
|
NSString *base64 = [data base64Encoding_xcd];
|
||||||
|
[data release];
|
||||||
|
imageFilePath = [NSString stringWithFormat:@"\"data:%@;base64,%@\"", mimeType, base64];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *func = [NSString stringWithFormat:@"tentia_instance.sendNewMessage(\"%@\", \"%@\", \"%@\", %@, %@)",
|
||||||
text,
|
text,
|
||||||
post.inReplyTostatusId,
|
post.inReplyTostatusId,
|
||||||
post.inReplyToEntity,
|
post.inReplyToEntity,
|
||||||
locationObject];
|
locationObject,
|
||||||
|
imageFilePath];
|
||||||
|
|
||||||
[timelineView stringByEvaluatingJavaScriptFromString:func];
|
[timelineView stringByEvaluatingJavaScriptFromString:func];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,15 +184,23 @@
|
||||||
<string key="NSTitle">Add current location</string>
|
<string key="NSTitle">Add current location</string>
|
||||||
<string key="NSKeyEquiv"/>
|
<string key="NSKeyEquiv"/>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<int key="NSMnemonicLoc">2147483647</int>
|
||||||
<object class="NSCustomResource" key="NSOnImage">
|
<object class="NSCustomResource" key="NSOnImage" id="400068421">
|
||||||
<string key="NSClassName">NSImage</string>
|
<string key="NSClassName">NSImage</string>
|
||||||
<string key="NSResourceName">NSMenuCheckmark</string>
|
<string key="NSResourceName">NSMenuCheckmark</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSCustomResource" key="NSMixedImage">
|
<object class="NSCustomResource" key="NSMixedImage" id="196417858">
|
||||||
<string key="NSClassName">NSImage</string>
|
<string key="NSClassName">NSImage</string>
|
||||||
<string key="NSResourceName">NSMenuMixedState</string>
|
<string key="NSResourceName">NSMenuMixedState</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="NSMenuItem" id="502380341">
|
||||||
|
<reference key="NSMenu" ref="723763594"/>
|
||||||
|
<string key="NSTitle">Add image</string>
|
||||||
|
<string key="NSKeyEquiv"/>
|
||||||
|
<int key="NSMnemonicLoc">2147483647</int>
|
||||||
|
<reference key="NSOnImage" ref="400068421"/>
|
||||||
|
<reference key="NSMixedImage" ref="196417858"/>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
|
@ -263,6 +271,14 @@
|
||||||
</object>
|
</object>
|
||||||
<int key="connectionID">100054</int>
|
<int key="connectionID">100054</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBActionConnection" key="connection">
|
||||||
|
<string key="label">addImage:</string>
|
||||||
|
<reference key="source" ref="512844837"/>
|
||||||
|
<reference key="destination" ref="502380341"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">100056</int>
|
||||||
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBOutletConnection" key="connection">
|
<object class="IBOutletConnection" key="connection">
|
||||||
<string key="label">delegate</string>
|
<string key="label">delegate</string>
|
||||||
|
@ -378,6 +394,7 @@
|
||||||
<object class="NSMutableArray" key="children">
|
<object class="NSMutableArray" key="children">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<reference ref="921309347"/>
|
<reference ref="921309347"/>
|
||||||
|
<reference ref="502380341"/>
|
||||||
</object>
|
</object>
|
||||||
<reference key="parent" ref="0"/>
|
<reference key="parent" ref="0"/>
|
||||||
</object>
|
</object>
|
||||||
|
@ -386,6 +403,11 @@
|
||||||
<reference key="object" ref="921309347"/>
|
<reference key="object" ref="921309347"/>
|
||||||
<reference key="parent" ref="723763594"/>
|
<reference key="parent" ref="723763594"/>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">100055</int>
|
||||||
|
<reference key="object" ref="502380341"/>
|
||||||
|
<reference key="parent" ref="723763594"/>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||||
|
@ -403,6 +425,7 @@
|
||||||
<string>100040.IBPluginDependency</string>
|
<string>100040.IBPluginDependency</string>
|
||||||
<string>100041.IBPluginDependency</string>
|
<string>100041.IBPluginDependency</string>
|
||||||
<string>100043.IBPluginDependency</string>
|
<string>100043.IBPluginDependency</string>
|
||||||
|
<string>100055.IBPluginDependency</string>
|
||||||
<string>5.IBPluginDependency</string>
|
<string>5.IBPluginDependency</string>
|
||||||
<string>5.IBWindowTemplateEditedContentRect</string>
|
<string>5.IBWindowTemplateEditedContentRect</string>
|
||||||
<string>6.IBPluginDependency</string>
|
<string>6.IBPluginDependency</string>
|
||||||
|
@ -421,6 +444,7 @@
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string>{{127, 736}, {299, 113}}</string>
|
<string>{{127, 736}, {299, 113}}</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
</object>
|
</object>
|
||||||
|
@ -437,7 +461,7 @@
|
||||||
<reference key="dict.values" ref="0"/>
|
<reference key="dict.values" ref="0"/>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">100054</int>
|
<int key="maxID">100056</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
|
|
13
Mac/MimeType.h
Normal file
13
Mac/MimeType.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// MimeType.h
|
||||||
|
// Tentia
|
||||||
|
//
|
||||||
|
// Created by Jeena on 23/11/2012.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface MimeType : NSObject
|
||||||
|
+(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err;
|
||||||
|
@end
|
27
Mac/MimeType.m
Normal file
27
Mac/MimeType.m
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// MimeType.m
|
||||||
|
// Tentia
|
||||||
|
//
|
||||||
|
// Created by Jeena on 23/11/2012.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MimeType.h"
|
||||||
|
|
||||||
|
@implementation MimeType
|
||||||
|
|
||||||
|
+(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err {
|
||||||
|
NSString *uti, *mimeType = nil;
|
||||||
|
|
||||||
|
if (!(uti = [[NSWorkspace sharedWorkspace] typeOfFile:path error:err]))
|
||||||
|
return nil;
|
||||||
|
if (err)
|
||||||
|
*err = nil;
|
||||||
|
|
||||||
|
if ((mimeType = (NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)uti, kUTTagClassMIMEType)))
|
||||||
|
mimeType = NSMakeCollectable(mimeType);
|
||||||
|
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
46
Mac/NSData+Base64.h
Normal file
46
Mac/NSData+Base64.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// Created by Cédric Luthi on 2012-02-24.
|
||||||
|
// Copyright (c) 2012 Cédric Luthi. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NSData+Base64.h"
|
||||||
|
|
||||||
|
#ifndef __has_feature
|
||||||
|
#define __has_feature(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@implementation NSData (Base64)
|
||||||
|
|
||||||
|
+ (id) dataWithBase64Encoding_xcd:(NSString *)base64Encoding
|
||||||
|
{
|
||||||
|
if ([base64Encoding length] % 4 != 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
NSString *plist = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?><plist version=\"1.0\"><data>%@</data></plist>", base64Encoding];
|
||||||
|
return [NSPropertyListSerialization propertyListWithData:[plist dataUsingEncoding:NSASCIIStringEncoding] options:0 format:NULL error:NULL];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) base64Encoding_xcd
|
||||||
|
{
|
||||||
|
NSData *plist = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL];
|
||||||
|
NSRange fullRange = NSMakeRange(0, [plist length]);
|
||||||
|
NSRange startRange = [plist rangeOfData:[@"<data>" dataUsingEncoding:NSASCIIStringEncoding] options:0 range:fullRange];
|
||||||
|
NSRange endRange = [plist rangeOfData:[@"</data>" dataUsingEncoding:NSASCIIStringEncoding] options:NSDataSearchBackwards range:fullRange];
|
||||||
|
if (startRange.location == NSNotFound || endRange.location == NSNotFound)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
NSUInteger base64Location = startRange.location + startRange.length;
|
||||||
|
NSUInteger base64length = endRange.location - base64Location;
|
||||||
|
NSData *base64Data = [NSData dataWithBytesNoCopy:(void *)((uintptr_t)base64Location + (uintptr_t)[plist bytes]) length:base64length freeWhenDone:NO];
|
||||||
|
NSString *base64Encoding = [[NSString alloc] initWithData:base64Data encoding:NSASCIIStringEncoding];
|
||||||
|
base64Encoding = [base64Encoding stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
base64Encoding = [base64Encoding stringByReplacingOccurrencesOfString:@"\n" withString:@""];
|
||||||
|
|
||||||
|
#if __has_feature(objc_arc)
|
||||||
|
return base64Encoding;
|
||||||
|
#else
|
||||||
|
return [base64Encoding autorelease];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
13
Mac/NSData+Base64.m
Normal file
13
Mac/NSData+Base64.m
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// Created by Cédric Luthi on 2012-02-24.
|
||||||
|
// Copyright (c) 2012 Cédric Luthi. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface NSData (Base64)
|
||||||
|
|
||||||
|
+ (id) dataWithBase64Encoding_xcd:(NSString *)base64String;
|
||||||
|
- (NSString *) base64Encoding_xcd;
|
||||||
|
|
||||||
|
@end
|
|
@ -11,7 +11,7 @@
|
||||||
#import <CoreLocation/CoreLocation.h>
|
#import <CoreLocation/CoreLocation.h>
|
||||||
|
|
||||||
|
|
||||||
@interface NewMessageWindow : NSDocument <NSTextFieldDelegate, CLLocationManagerDelegate>
|
@interface NewMessageWindow : NSDocument <NSTextFieldDelegate, CLLocationManagerDelegate, NSOpenSavePanelDelegate>
|
||||||
{
|
{
|
||||||
IBOutlet NSTextField *textField;
|
IBOutlet NSTextField *textField;
|
||||||
IBOutlet NSTextField *counter;
|
IBOutlet NSTextField *counter;
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
NSMenuItem *addImage;
|
NSMenuItem *addImage;
|
||||||
CLLocationManager *locationManager;
|
CLLocationManager *locationManager;
|
||||||
CLLocation *currentLocation;
|
CLLocation *currentLocation;
|
||||||
|
NSString *imageFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, retain) IBOutlet NSTextField *textField;
|
@property (nonatomic, retain) IBOutlet NSTextField *textField;
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
@property (assign) IBOutlet NSButton *addMenuButton;
|
@property (assign) IBOutlet NSButton *addMenuButton;
|
||||||
@property (retain, nonatomic) CLLocationManager *locationManager;
|
@property (retain, nonatomic) CLLocationManager *locationManager;
|
||||||
@property (retain, nonatomic) CLLocation *currentLocation;
|
@property (retain, nonatomic) CLLocation *currentLocation;
|
||||||
|
@property (retain, nonatomic) NSString *imageFilePath;
|
||||||
|
|
||||||
- (IBAction)sendTweet:(NSControl *)control;
|
- (IBAction)sendTweet:(NSControl *)control;
|
||||||
- (void)inReplyTo:(NSString *)userName statusId:(NSString *)statusId withString:(NSString *)string;
|
- (void)inReplyTo:(NSString *)userName statusId:(NSString *)statusId withString:(NSString *)string;
|
||||||
|
|
|
@ -22,12 +22,14 @@
|
||||||
@synthesize addMenuButton;
|
@synthesize addMenuButton;
|
||||||
@synthesize textField, counter;
|
@synthesize textField, counter;
|
||||||
@synthesize locationManager, currentLocation;
|
@synthesize locationManager, currentLocation;
|
||||||
|
@synthesize imageFilePath;
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[locationManager stopUpdatingLocation];
|
[locationManager stopUpdatingLocation];
|
||||||
[locationManager release];
|
[locationManager release];
|
||||||
[currentLocation release];
|
[currentLocation release];
|
||||||
|
[imageFilePath release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,10 +141,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)addImage:(id)sender
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)openAddMenu:(id)sender
|
- (IBAction)openAddMenu:(id)sender
|
||||||
{
|
{
|
||||||
NSRect frame = [(NSButton *)sender frame];
|
NSRect frame = [(NSButton *)sender frame];
|
||||||
|
@ -203,6 +201,7 @@
|
||||||
post.inReplyTostatusId = inReplyTostatusId;
|
post.inReplyTostatusId = inReplyTostatusId;
|
||||||
post.inReplyToEntity = inReplyToEntity;
|
post.inReplyToEntity = inReplyToEntity;
|
||||||
post.location = self.currentLocation;
|
post.location = self.currentLocation;
|
||||||
|
post.imageFilePath = self.imageFilePath;
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"sendTweet" object:post];
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"sendTweet" object:post];
|
||||||
[self close];
|
[self close];
|
||||||
} else {
|
} else {
|
||||||
|
@ -246,4 +245,66 @@
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark Add images
|
||||||
|
|
||||||
|
- (IBAction)addImage:(id)sender
|
||||||
|
{
|
||||||
|
NSMenuItem *menuItem = (NSMenuItem *)sender;
|
||||||
|
|
||||||
|
if (!self.imageFilePath)
|
||||||
|
{
|
||||||
|
[menuItem setTitle:@"Remove image"];
|
||||||
|
|
||||||
|
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
|
||||||
|
[openDlg setPrompt:@"Select"];
|
||||||
|
[openDlg setDelegate:self];
|
||||||
|
|
||||||
|
// Enable the selection of files in the dialog.
|
||||||
|
[openDlg setCanChooseFiles:YES];
|
||||||
|
|
||||||
|
// Enable the selection of directories in the dialog.
|
||||||
|
[openDlg setCanChooseDirectories:NO];
|
||||||
|
|
||||||
|
// Display the dialog. If the OK button was pressed,
|
||||||
|
// process the files.
|
||||||
|
if ( [openDlg runModalForDirectory:nil file:nil] == NSOKButton )
|
||||||
|
{
|
||||||
|
// Get an array containing the full filenames of all
|
||||||
|
// files and directories selected.
|
||||||
|
NSArray* files = [openDlg filenames];
|
||||||
|
|
||||||
|
// Loop through all the files and process them.
|
||||||
|
for( int i = 0; i < [files count]; i++ )
|
||||||
|
{
|
||||||
|
self.imageFilePath = [files objectAtIndex:i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.imageFilePath = nil;
|
||||||
|
[menuItem setTitle:@"Add image"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
|
||||||
|
{
|
||||||
|
NSString* ext = [filename pathExtension];
|
||||||
|
if (ext == @"" || ext == @"/" || ext == nil || ext == NULL || [ext length] < 1) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSEnumerator* tagEnumerator = [[NSArray arrayWithObjects:@"png", @"jpg", @"gif", @"jpeg", nil] objectEnumerator];
|
||||||
|
NSString* allowedExt;
|
||||||
|
while ((allowedExt = [tagEnumerator nextObject]))
|
||||||
|
{
|
||||||
|
if ([ext caseInsensitiveCompare:allowedExt] == NSOrderedSame)
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
NSString *inReplyTostatusId;
|
NSString *inReplyTostatusId;
|
||||||
NSString *inReplyToEntity;
|
NSString *inReplyToEntity;
|
||||||
CLLocation *location;
|
CLLocation *location;
|
||||||
NSImage *image;
|
NSString *imageFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, retain) NSString *text;
|
@property (nonatomic, retain) NSString *text;
|
||||||
@property (nonatomic, retain) NSString *inReplyTostatusId;
|
@property (nonatomic, retain) NSString *inReplyTostatusId;
|
||||||
@property (nonatomic, retain) NSString *inReplyToEntity;
|
@property (nonatomic, retain) NSString *inReplyToEntity;
|
||||||
@property (nonatomic, retain) CLLocation *location;
|
@property (nonatomic, retain) CLLocation *location;
|
||||||
@property (nonatomic, retain) NSImage *image;
|
@property (nonatomic, retain) NSString *imageFilePath;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
@implementation PostModel
|
@implementation PostModel
|
||||||
|
|
||||||
@synthesize text, inReplyTostatusId, inReplyToEntity, location, image;
|
@synthesize text, inReplyTostatusId, inReplyToEntity, location, imageFilePath;
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
[inReplyTostatusId release];
|
[inReplyTostatusId release];
|
||||||
[inReplyToEntity release];
|
[inReplyToEntity release];
|
||||||
[location release];
|
[location release];
|
||||||
[image release];
|
[imageFilePath release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F618EC912DB5E6100E500D9 /* PostModel.m */; };
|
1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F618EC912DB5E6100E500D9 /* PostModel.m */; };
|
||||||
1F70619F1178FBB300C85707 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F70619E1178FBB300C85707 /* Carbon.framework */; };
|
1F70619F1178FBB300C85707 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F70619E1178FBB300C85707 /* Carbon.framework */; };
|
||||||
1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F77DB46118C5F1C007C7F1E /* Constants.m */; };
|
1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F77DB46118C5F1C007C7F1E /* Constants.m */; };
|
||||||
|
1F880B6B165EE0F60022A84D /* NSData+Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F880B6A165EE0F60022A84D /* NSData+Base64.m */; };
|
||||||
|
1F880B6E165FE8890022A84D /* MimeType.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F880B6D165FE8890022A84D /* MimeType.m */; };
|
||||||
1FA09847144602530079E258 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FA09846144602530079E258 /* libicucore.dylib */; };
|
1FA09847144602530079E258 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FA09846144602530079E258 /* libicucore.dylib */; };
|
||||||
1FC254A01427DFAD0035D84B /* AccessToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FC2549B1427D9930035D84B /* AccessToken.m */; };
|
1FC254A01427DFAD0035D84B /* AccessToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FC2549B1427D9930035D84B /* AccessToken.m */; };
|
||||||
1FDEF722164EFE9100F927F3 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FDEF721164EFE9100F927F3 /* Growl.framework */; };
|
1FDEF722164EFE9100F927F3 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FDEF721164EFE9100F927F3 /* Growl.framework */; };
|
||||||
|
@ -64,6 +66,10 @@
|
||||||
1F70619E1178FBB300C85707 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
1F70619E1178FBB300C85707 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
||||||
1F77DB45118C5F1C007C7F1E /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Constants.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
1F77DB45118C5F1C007C7F1E /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Constants.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||||
1F77DB46118C5F1C007C7F1E /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Constants.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
1F77DB46118C5F1C007C7F1E /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Constants.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||||
|
1F880B69165EE0F60022A84D /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Base64.h"; sourceTree = "<group>"; };
|
||||||
|
1F880B6A165EE0F60022A84D /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Base64.m"; sourceTree = "<group>"; };
|
||||||
|
1F880B6C165FE8890022A84D /* MimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MimeType.h; sourceTree = "<group>"; };
|
||||||
|
1F880B6D165FE8890022A84D /* MimeType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MimeType.m; sourceTree = "<group>"; };
|
||||||
1FA09846144602530079E258 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
|
1FA09846144602530079E258 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
|
||||||
1FC2549A1427D9930035D84B /* AccessToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AccessToken.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
1FC2549A1427D9930035D84B /* AccessToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AccessToken.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||||
1FC2549B1427D9930035D84B /* AccessToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AccessToken.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
1FC2549B1427D9930035D84B /* AccessToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AccessToken.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||||
|
@ -165,6 +171,10 @@
|
||||||
1F618EC912DB5E6100E500D9 /* PostModel.m */,
|
1F618EC912DB5E6100E500D9 /* PostModel.m */,
|
||||||
1FC2549A1427D9930035D84B /* AccessToken.h */,
|
1FC2549A1427D9930035D84B /* AccessToken.h */,
|
||||||
1FC2549B1427D9930035D84B /* AccessToken.m */,
|
1FC2549B1427D9930035D84B /* AccessToken.m */,
|
||||||
|
1F880B69165EE0F60022A84D /* NSData+Base64.h */,
|
||||||
|
1F880B6A165EE0F60022A84D /* NSData+Base64.m */,
|
||||||
|
1F880B6C165FE8890022A84D /* MimeType.h */,
|
||||||
|
1F880B6D165FE8890022A84D /* MimeType.m */,
|
||||||
);
|
);
|
||||||
name = Classes;
|
name = Classes;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -282,6 +292,8 @@
|
||||||
1FFA36D81177D879006C8562 /* ViewDelegate.m in Sources */,
|
1FFA36D81177D879006C8562 /* ViewDelegate.m in Sources */,
|
||||||
1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */,
|
1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */,
|
||||||
1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */,
|
1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */,
|
||||||
|
1F880B6B165EE0F60022A84D /* NSData+Base64.m in Sources */,
|
||||||
|
1F880B6E165FE8890022A84D /* MimeType.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
<description>Most recent changes with links to updates.</description>
|
<description>Most recent changes with links to updates.</description>
|
||||||
<language>en</language>
|
<language>en</language>
|
||||||
<item>
|
<item>
|
||||||
<title>Version 0.2.4</title>
|
<title>Version 0.3.0</title>
|
||||||
<sparkle:minimumSystemVersion>10.5.0</sparkle:minimumSystemVersion>
|
<sparkle:minimumSystemVersion>10.5.0</sparkle:minimumSystemVersion>
|
||||||
<sparkle:releaseNotesLink>http://jabs.nu/Tentia/download/ReleaseNotes.html</sparkle:releaseNotesLink>
|
<sparkle:releaseNotesLink>http://jabs.nu/Tentia/download/ReleaseNotes.html</sparkle:releaseNotesLink>
|
||||||
<pubDate>Sat, 17 Nov 2012 20:45:22 +0100</pubDate>
|
<pubDate>Thu, 22 Nov 2012 22:01:49 +0100</pubDate>
|
||||||
<enclosure url="http://jabs.nu/Tentia/download/Tentia.app.zip"
|
<enclosure url="http://jabs.nu/Tentia/download/Tentia.app.zip"
|
||||||
sparkle:version="0.2.4"
|
sparkle:version="0.3.0"
|
||||||
length="1069130"
|
length="1031876"
|
||||||
type="application/octet-stream"
|
type="application/octet-stream"
|
||||||
sparkle:dsaSignature="MC0CFCvZgr1pcB0bW0IQ8E7ffqs0SjvpAhUAioix/kjwYUqGqchCTDN6EjncmSE=" />
|
sparkle:dsaSignature="MC0CFQCMY1g2OMW21BMQWoaZjUzMxY+kwQIUdMZXIOCTcGv+4Ht5wcIr07F4dao=" />
|
||||||
</item>
|
</item>
|
||||||
</channel>
|
</channel>
|
||||||
</rss>
|
</rss>
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
<p>Implemented remove deleted posts</p>
|
<p>Implemented remove deleted posts</p>
|
||||||
<p>Added a JS and CSS Plugin API</p>
|
<p>Added a JS and CSS Plugin API</p>
|
||||||
<p>Implemented adding location to post</p>
|
<p>Implemented adding location to post</p>
|
||||||
|
<p>Implemented blue right border if you're mentioned in a post</p>
|
||||||
<p>Bugfixes</p>
|
<p>Bugfixes</p>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
|
@ -117,10 +117,10 @@ function(Core, Paths, HostApp, URI) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeline.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location) {
|
Timeline.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
var callback = function(data) { _this.getNewData(); }
|
var callback = function(data) { _this.getNewData(); }
|
||||||
Core.prototype.sendNewMessage.call(this, content, in_reply_to_status_id, in_reply_to_entity, location, callback);
|
Core.prototype.sendNewMessage.call(this, content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeline.prototype.remove = function(id) {
|
Timeline.prototype.remove = function(id) {
|
||||||
|
|
|
@ -258,20 +258,54 @@ function(jQuery, Paths, URI, HostApp, Followings) {
|
||||||
return template.item;
|
return template.item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, callback) {
|
Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_file_path, callback) {
|
||||||
|
|
||||||
|
if (image_file_path) {
|
||||||
|
|
||||||
|
this.sendNewMessageWithImage(content, in_reply_to_status_id, in_reply_to_entity, location, image_file_path, callback);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var url = URI(Paths.mkApiRootPath("/posts"));
|
||||||
|
|
||||||
|
var http_method = "POST";
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
"type": "https://tent.io/types/post/status/v0.1.0",
|
||||||
|
"published_at": parseInt(new Date().getTime() / 1000, 10),
|
||||||
|
"permissions": {
|
||||||
|
"public": true
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"text": content,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (location) {
|
||||||
|
data["content"]["location"] = { "type": "Point", "coordinates": location }
|
||||||
|
}
|
||||||
|
|
||||||
|
var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
|
||||||
|
if (mentions.length > 0) {
|
||||||
|
data["mentions"] = mentions;
|
||||||
|
}
|
||||||
|
|
||||||
|
Paths.getURL(url.toString(), http_method, callback, JSON.stringify(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core.prototype.sendNewMessageWithImage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, callback) {
|
||||||
|
|
||||||
var url = URI(Paths.mkApiRootPath("/posts"));
|
var url = URI(Paths.mkApiRootPath("/posts"));
|
||||||
|
|
||||||
var http_method = "POST";
|
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
"type": "https://tent.io/types/post/status/v0.1.0",
|
"type": "https://tent.io/types/post/photo/v0.1.0",
|
||||||
"published_at": (new Date().getTime() / 1000),
|
"published_at": parseInt(new Date().getTime() / 1000, 10),
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"public": true
|
"public": true
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"text": content,
|
"caption": content,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -280,12 +314,41 @@ function(jQuery, Paths, URI, HostApp, Followings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
|
var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
|
||||||
|
|
||||||
if (mentions.length > 0) {
|
if (mentions.length > 0) {
|
||||||
data["mentions"] = mentions;
|
data["mentions"] = mentions;
|
||||||
}
|
}
|
||||||
|
|
||||||
Paths.getURL(url.toString(), http_method, callback, JSON.stringify(data));
|
var data_string = JSON.stringify(data);
|
||||||
|
|
||||||
|
var boundary = "-----------TentAttachment";
|
||||||
|
var post = boundary + "\r\n";
|
||||||
|
|
||||||
|
post += 'Content-Disposition: form-data; name="post"; filename="post.json"\r\n';
|
||||||
|
post += 'Content-Length: ' + data_string.length + '\r\n';
|
||||||
|
post += 'Content-Type: application/vnd.tent.v0+json\r\n';
|
||||||
|
post += 'Content-Transfer-Encoding: binary\r\n\r\n';
|
||||||
|
post += data_string;
|
||||||
|
|
||||||
|
post += "\r\n" + boundary + "\r\n";
|
||||||
|
|
||||||
|
var binary_data = this.dataURItoBlob(image_data_uri);
|
||||||
|
var ext = "png";
|
||||||
|
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
|
||||||
|
var blob_string = e.target.result;
|
||||||
|
post += 'Content-Disposition: form-data; name="photos[0]"; filename="photo.' + ext + '"\r\n';
|
||||||
|
post += 'Content-Length: ' + blob_string.length + "\r\n";
|
||||||
|
post += 'Content-Type: ' + binary_data.mime_type + "\r\n";
|
||||||
|
post += 'Content-Transfer-Encoding: binary\r\n\r\n';
|
||||||
|
post += image_data_uri.split(',')[1];
|
||||||
|
post += "\r\n" + boundary + "--\r\n";
|
||||||
|
|
||||||
|
Paths.postMultipart(url.toString(), callback, post, boundary);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.readAsBinaryString(binary_data.blob)
|
||||||
}
|
}
|
||||||
|
|
||||||
Core.prototype.remove = function(id, callback) {
|
Core.prototype.remove = function(id, callback) {
|
||||||
|
@ -475,6 +538,30 @@ function(jQuery, Paths, URI, HostApp, Followings) {
|
||||||
HostApp.openNewMessageWidow(entity, status_id, string);
|
HostApp.openNewMessageWidow(entity, status_id, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core.prototype.dataURItoBlob = function(dataURI) {
|
||||||
|
// convert base64 to raw binary data held in a string
|
||||||
|
// doesn't handle URLEncoded DataURIs
|
||||||
|
var byteString = atob(dataURI.split(',')[1]);
|
||||||
|
|
||||||
|
// separate out the mime component
|
||||||
|
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
|
||||||
|
|
||||||
|
// write the bytes of the string to an ArrayBuffer
|
||||||
|
var ab = new ArrayBuffer(byteString.length);
|
||||||
|
var ia = new Uint8Array(ab);
|
||||||
|
for (var i = 0; i < byteString.length; i++) {
|
||||||
|
ia[i] = byteString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the ArrayBuffer to a blob, and you're done
|
||||||
|
var blob = new Blob([ab], {type: mimeString});
|
||||||
|
return {
|
||||||
|
mime_type: mimeString,
|
||||||
|
blob: blob,
|
||||||
|
base64: byteString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Core;
|
return Core;
|
||||||
|
|
||||||
});
|
});
|
|
@ -60,6 +60,44 @@ function(jQuery, HostApp, Hmac) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Paths.postMultipart = function(url, callback, data, boundary) {
|
||||||
|
debug(url)
|
||||||
|
debug(data)
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
|
||||||
|
beforeSend: function(xhr) {
|
||||||
|
|
||||||
|
if (data) xhr.setRequestHeader("Content-Length", data.length);
|
||||||
|
debug("Content-Length: " + data.length);
|
||||||
|
|
||||||
|
var user_access_token = HostApp.stringForKey("user_access_token");
|
||||||
|
|
||||||
|
if (user_access_token) {
|
||||||
|
|
||||||
|
auth_header = Hmac.makeAuthHeader(
|
||||||
|
url,
|
||||||
|
"POST",
|
||||||
|
HostApp.stringForKey("user_mac_key"),
|
||||||
|
user_access_token
|
||||||
|
);
|
||||||
|
debug(auth_header)
|
||||||
|
xhr.setRequestHeader("Authorization", auth_header);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
url: url,
|
||||||
|
accepts: "application/vnd.tent.v0+json",
|
||||||
|
contentType: "multipart/form-data;boundary=" + boundary,
|
||||||
|
type: "POST",
|
||||||
|
complete: callback,
|
||||||
|
data: data,
|
||||||
|
processData: false,
|
||||||
|
error: function(xhr, ajaxOptions, thrownError) {
|
||||||
|
console.error("postMultipart " + xhr.statusText + " (" + url + "): '" + xhr.responseText + "'");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Paths.findProfileURL = function(entity, callback, errorCallback) {
|
Paths.findProfileURL = function(entity, callback, errorCallback) {
|
||||||
|
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
|
|
Reference in a new issue