trying to add images

This commit is contained in:
Jeena Paradies 2012-11-24 00:16:51 +01:00
parent 555e7cca3c
commit a128e0278d
17 changed files with 369 additions and 31 deletions

View file

@ -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;

View file

@ -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];
} }

View file

@ -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
View 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
View 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
View 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
View 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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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];
} }

View file

@ -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;
}; };

View file

@ -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>

View file

@ -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 />

View file

@ -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) {

View file

@ -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;
}); });

View file

@ -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({