add share button and implement AirDrop share in OSX, update info.plist to set on Mac OS the default app for PPI, on iOS include the Documents/Inbox subfolder used to store the received files from AirDrop

This commit is contained in:
2018-10-12 11:37:08 +02:00
parent bc0ac5d893
commit 7708f3dc74
13 changed files with 208 additions and 20 deletions

View File

@@ -4,6 +4,33 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ppi</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>pp-icon-square</string>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeMIMETypes</key>
<array/>
<key>CFBundleTypeName</key>
<string>PanoPainter Image</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSIsAppleDefaultForType</key>
<true/>
<key>LSItemContentTypes</key>
<array>
<string>public.panorama-image</string>
</array>
<key>LSTypeIsPackage</key>
<integer>0</integer>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
@@ -30,5 +57,67 @@
<string>Copyright © 2018 OmixLab Ltd. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>PanoPainter Image</string>
<key>UTTypeIconFile</key>
<string>pp-icon-square</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>public.panorama-image</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>com.apple.ostype</key>
<array>
<string>****</string>
</array>
<key>public.filename-extension</key>
<array>
<string>ppi</string>
</array>
<key>public.mime-type</key>
<array>
<string>image/ppi</string>
</array>
</dict>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>PanoPainter Image</string>
<key>UTTypeIconFile</key>
<string>pp-icon-square</string>
<key>UTTypeIdentifier</key>
<string>com.panopainter.image</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>com.apple.ostype</key>
<array>
<string>****</string>
</array>
<key>public.filename-extension</key>
<array>
<string>ppi</string>
</array>
<key>public.mime-type</key>
<array>
<string>image/ppi</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

View File

@@ -21,6 +21,9 @@ std::deque<std::packaged_task<void()>> tasklist;
std::mutex task_mutex;
@implementation View
{
NSSharingService *airdrop_service;
}
- (void)async_lock
{
CGLLockContext([glctx CGLContextObj]);
@@ -81,8 +84,39 @@ std::mutex task_mutex;
}
return ret;
}
- (void)share_file:(NSString*)file_path
{
NSURL *url = [NSURL fileURLWithPath:file_path];
NSArray *objectsToShare = @[url];
//
// UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil];
//
// // Exclude all activities except AirDrop.
// NSArray *excludedActivities = @[UIActivityTypePostToTwitter, UIActivityTypePostToFacebook,
// UIActivityTypePostToWeibo,
// UIActivityTypeMessage, UIActivityTypeMail,
// UIActivityTypePrint, UIActivityTypeCopyToPasteboard,
// UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll,
// UIActivityTypeAddToReadingList, UIActivityTypePostToFlickr,
// UIActivityTypePostToVimeo, UIActivityTypePostToTencentWeibo];
// controller.excludedActivityTypes = excludedActivities;
//
// // Present the controller
// [self presentViewController:controller animated:YES completion:nil];
[airdrop_service performWithItems:objectsToShare];
}
- (NSWindow *)sharingService:(NSSharingService *)sharingService sourceWindowForShareItems:(NSArray *)items sharingContentScope:(NSSharingContentScope *)sharingContentScope
{
return self.window;
}
- (NSView *)anchoringViewForSharingService:(NSSharingService *)sharingService showRelativeToRect:(NSRect *)positioningRect preferredEdge:(NSRectEdge *)preferredEdge
{
return self;
}
- (instancetype)initWithFrame:(NSRect)frameRect
{
airdrop_service = [NSSharingService sharingServiceNamed:NSSharingServiceNameSendViaAirDrop];
airdrop_service.delegate = self;
gl_ready = false;
NSOpenGLPixelFormatAttribute attrs[] =
{
@@ -134,6 +168,12 @@ std::mutex task_mutex;
App::I.init();
CGLUnlockContext([[self openGLContext] CGLContextObj]);
gl_ready = true;
if ([file2open length] > 0)
{
LOG("open file %s", [file2open UTF8String]);
App::I.open_document([file2open UTF8String]);
}
}
- (void)terminateGL
@@ -428,6 +468,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
Window* window;
Controller* controller;
View* view;
NSString* file2open;
}
@end @implementation AppOSX
- (instancetype)init
@@ -437,6 +478,13 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
[self setDelegate:self];
return self;
}
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename
{
LOG("open file %s", [filename UTF8String]);
//App::I.open_document([filename UTF8String]);
file2open = filename;
return YES;
}
- (void)applicationWillTerminate:(NSNotification *)notification
{
[view terminateGL];
@@ -458,6 +506,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
NSRect r = NSMakeRect(0, 0, App::I.width, App::I.height);
view = [[View alloc] initWithFrame:r];
view->file2open = file2open;
controller = [[Controller alloc] initWithWindow:window];
App::I.osx_view = view;

View File

@@ -9,13 +9,14 @@
@interface Controller : NSWindowController<NSWindowDelegate>
@end
@interface View : NSOpenGLView
@interface View : NSOpenGLView<NSSharingServiceDelegate>
{
@public Window* wnd;
CVDisplayLinkRef dl;
NSOpenGLContext* glctx;
_CGLContextObject* cgl;
bool gl_ready;
@public NSString* file2open;
}
- (void)close;
- (void)terminateGL;
@@ -24,4 +25,5 @@
- (void)async_swap;
- (std::string)pick_file:(NSArray<NSString*>*)types;
- (std::string)pick_dir;
- (void)share_file:(NSString*)file_path;
@end

View File

@@ -134,8 +134,6 @@
ADC0EB3F1FBDC748004079BB /* node_colorwheel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC0EB3B1FBDC748004079BB /* node_colorwheel.cpp */; };
ADC0EB431FC36E88004079BB /* node_dialog_picker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC0EB401FC36E88004079BB /* node_dialog_picker.cpp */; };
ADC0EB441FC36E88004079BB /* node_dialog_picker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC0EB401FC36E88004079BB /* node_dialog_picker.cpp */; };
ADC6B6C8216E0F0000DED870 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = ADC6B6C7216E0F0000DED870 /* sqlite3.c */; };
ADC6B6C9216E0F0D00DED870 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = ADC6B6C7216E0F0000DED870 /* sqlite3.c */; };
ADC6F4621F3AFF2C004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; };
ADC6F4631F3AFF2D004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; };
ADC6F4671F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; };
@@ -200,6 +198,8 @@
ADE4911F1F86E65E00FB8E92 /* sweep.cc in Sources */ = {isa = PBXBuildFile; fileRef = ADE491131F86D09100FB8E92 /* sweep.cc */; };
ADEBA9062069A4F40085AE16 /* objc_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADEBA9052069A4F40085AE16 /* objc_utils.cpp */; };
ADEBA9092069A50E0085AE16 /* objc_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADEBA9082069A50E0085AE16 /* objc_utils.cpp */; };
ADF396DD216F749200024722 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADF396DB216F6BD800024722 /* AppKit.framework */; };
ADF396DF216FA6C900024722 /* pp-icon-square.png in Resources */ = {isa = PBXBuildFile; fileRef = ADF396DE216FA6C700024722 /* pp-icon-square.png */; };
ADFD32152166AA0800F46F85 /* GenerateThumbnailForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = ADFD32142166AA0800F46F85 /* GenerateThumbnailForURL.c */; };
ADFD32172166AA0800F46F85 /* GeneratePreviewForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = ADFD32162166AA0800F46F85 /* GeneratePreviewForURL.c */; };
ADFD32192166AA0800F46F85 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = ADFD32182166AA0800F46F85 /* main.c */; };
@@ -467,6 +467,8 @@
ADEBA9052069A4F40085AE16 /* objc_utils.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = objc_utils.cpp; path = src/objc_utils.cpp; sourceTree = SOURCE_ROOT; };
ADEBA9072069A50E0085AE16 /* objc_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = objc_utils.h; path = src/objc_utils.h; sourceTree = SOURCE_ROOT; };
ADEBA9082069A50E0085AE16 /* objc_utils.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = objc_utils.cpp; path = src/objc_utils.cpp; sourceTree = SOURCE_ROOT; };
ADF396DB216F6BD800024722 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
ADF396DE216FA6C700024722 /* pp-icon-square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "pp-icon-square.png"; path = "extra/pp-icon-square.png"; sourceTree = "<group>"; };
ADFD32122166AA0800F46F85 /* QLPlugin.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QLPlugin.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
ADFD32142166AA0800F46F85 /* GenerateThumbnailForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GenerateThumbnailForURL.c; sourceTree = "<group>"; };
ADFD32162166AA0800F46F85 /* GeneratePreviewForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GeneratePreviewForURL.c; sourceTree = "<group>"; };
@@ -487,6 +489,7 @@
AD0E5CB11ECC726C00C35669 /* OpenGL.framework in Frameworks */,
AD0E5CB01ECC726400C35669 /* Cocoa.framework in Frameworks */,
AD0E5CAF1ECC726000C35669 /* CoreFoundation.framework in Frameworks */,
ADF396DD216F749200024722 /* AppKit.framework in Frameworks */,
AD0E5CAE1ECC725400C35669 /* CoreVideo.framework in Frameworks */,
ADC8F776216675A90084ECAD /* HockeySDK.framework in Frameworks */,
);
@@ -689,6 +692,7 @@
AD58E0461E107411006ACC15 = {
isa = PBXGroup;
children = (
ADF396DE216FA6C700024722 /* pp-icon-square.png */,
AD2286BC214E97460074567E /* scripts */,
AD58E0731E3421CB006ACC15 /* libs */,
AD58E0611E17F23D006ACC15 /* data */,
@@ -789,6 +793,7 @@
AD759B631F2793AD00211963 /* Frameworks */ = {
isa = PBXGroup;
children = (
ADF396DB216F6BD800024722 /* AppKit.framework */,
ADFD32232166B12A00F46F85 /* Foundation.framework */,
AD06989820CC6C3E0010825F /* OSX */,
AD06989520CC6C210010825F /* iOS */,
@@ -1077,6 +1082,7 @@
buildActionMask = 2147483647;
files = (
AD0E5CE41ECC76BA00C35669 /* data in Resources */,
ADF396DF216FA6C900024722 /* pp-icon-square.png in Resources */,
AD0E5CA51ECC6F2B00C35669 /* Assets.xcassets in Resources */,
AD0E5CA81ECC6F2B00C35669 /* MainMenu.xib in Resources */,
);
@@ -1303,7 +1309,6 @@
AD0E5CD61ECC72AD00C35669 /* bezier.cpp in Sources */,
AD0E5CB61ECC72AD00C35669 /* Yoga.c in Sources */,
ADE4911D1F86E65E00FB8E92 /* shapes.cc in Sources */,
ADC6B6C9216E0F0D00DED870 /* sqlite3.c in Sources */,
ADC0EB441FC36E88004079BB /* node_dialog_picker.cpp in Sources */,
AD0E5CC51ECC72AD00C35669 /* node_panel_color.cpp in Sources */,
AD0E5CD71ECC72AD00C35669 /* brush.cpp in Sources */,
@@ -1426,7 +1431,6 @@
ADD7D2A01EBF9E1C00D5A897 /* image.cpp in Sources */,
ADD7D2A11EBF9E1C00D5A897 /* texture.cpp in Sources */,
AD0E119C1ECA215600CDA6BB /* app_events.cpp in Sources */,
ADC6B6C8216E0F0000DED870 /* sqlite3.c in Sources */,
ADFD32272166C9A000F46F85 /* node_dialog_resize.cpp in Sources */,
ADBC8C551FAFD0520094B339 /* app_cloud.cpp in Sources */,
ADD7D2961EBF9E1C00D5A897 /* brush.cpp in Sources */,
@@ -1520,7 +1524,7 @@
);
INFOPLIST_FILE = "PanoPainter-OSX/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.7;
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_BUNDLE_IDENTIFIER = com.omixlab.panopainter.osx;
PRODUCT_NAME = PanoPainter;
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1544,7 +1548,7 @@
);
INFOPLIST_FILE = "PanoPainter-OSX/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.7;
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_BUNDLE_IDENTIFIER = com.omixlab.panopainter.osx;
PRODUCT_NAME = PanoPainter;
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@@ -7,6 +7,8 @@
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFile</key>
<string>pp-icon-square</string>
<key>CFBundleTypeExtensions</key>
<array>
<string>ppi</string>
@@ -16,7 +18,7 @@
<string>image/ppi</string>
</array>
<key>CFBundleTypeName</key>
<string>PPI</string>
<string>PanoPainter Image</string>
<key>CFBundleTypeRole</key>
<string>QLGenerator</string>
<key>LSItemContentTypes</key>
@@ -70,6 +72,8 @@
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIconFile</key>
<string>pp-icon-square</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>

View File

@@ -454,7 +454,7 @@
</border>
<node dir="row">
<node grow="1"><text os="win,osx" id="path" text="Workind dir: path" text-wrap-width="470" font-face="arial" font-size="11" margin="10 5 10 10"/></node>
<button id="btn-path" text="Set destination dir" width="140" height="30" margin="0 10 0 0"/>
<button os="win,osx" id="btn-path" text="Set destination dir" width="140" height="30" margin="0 10 0 0"/>
</node>
<node id="footer" height="40" dir="row" align="flex-end" justify="flex-end" pad="10">
<node grow="1"><button id="btn-delete" text="Delete Project" width="100" height="30" margin="0 10 0 0" color="1 0 0 1"/></node>
@@ -862,6 +862,10 @@ Here's a list of what's available in this release.
<icon icon="picture_go" width="20"/>
<text text="Export JPG" grow="1" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="file-share" text="Menu" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="picture_go" width="20"/>
<text text="Share" grow="1" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="file-resize" text="Menu" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="arrow_out" width="20"/>
<text text="Resize Document" grow="1" margin="0 0 0 5" font-face="arial" font-size="11"/>

BIN
extra/pp-icon-square.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -100,6 +100,7 @@ public:
void pick_file(std::vector<std::string> types, std::function<void(std::string path)> callback);
void pick_dir(std::function<void(std::string path)> callback);
void display_file(std::string path);
void share_file(std::string path);
void showKeyboard();
void hideKeyboard();
void initLog();

View File

@@ -253,7 +253,11 @@ void App::dialog_browse()
// load thumbnail test
auto dialog = std::make_shared<NodeDialogBrowse>();
dialog->m_manager = &layout;
dialog->search_path = work_path;
#ifdef __IOS__
dialog->search_paths = {work_path, data_path + "/Inbox"};
#else
dialog->search_paths = {work_path};
#endif
dialog->init();
dialog->create();
dialog->loaded();

View File

@@ -151,6 +151,21 @@ void App::display_file(std::string path)
#endif
}
void App::share_file(std::string path)
{
if (path.empty())
return;
#ifdef __IOS__
#elif __OSX__
dispatch_async(dispatch_get_main_queue(), ^{
[osx_view share_file:[NSString stringWithUTF8String:path.c_str()]];
});
#elif __ANDROID__
#elif _WIN32
// not implemented
#endif
}
bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source, bool eraser)
{
redraw = true;

View File

@@ -420,6 +420,12 @@ void App::init_menu_file()
popup->mouse_release();
popup->destroy();
};
if (auto b = popup->find<NodeButtonCustom>("file-share"))
b->on_click = [this](Node*) {
share_file(doc_path);
popup->mouse_release();
popup->destroy();
};
if (auto b = popup->find<NodeButtonCustom>("file-resize"))
b->on_click = [this](Node*) {
dialog_resize();

View File

@@ -88,7 +88,7 @@ void NodeDialogBrowse::init_controls()
realpath(path.c_str(), path_buffer);
#endif
working_path->set_text_format("Destination dir: %s", path_buffer);
search_path = path;
search_paths = {path};
clear_list();
init_list();
async_update();
@@ -122,19 +122,29 @@ void NodeDialogBrowse::clear_list()
void NodeDialogBrowse::init_list()
{
auto names = Asset::list_files(search_path, false, ".*\\.ppi");
for (const auto& n : names)
std::vector<std::tuple<std::string/*file-name*/, std::string/*path*/>> files;
for (auto sp : search_paths)
{
ui::Image thumb = ui::Canvas::I->thumbnail_read(search_path + "/" + n);
auto items = Asset::list_files(sp, false, ".*\\.ppi");
for (const auto& i : items)
{
files.push_back({i, sp + '/' + i});
}
}
for (const auto& f : files)
{
auto f_name = std::get<0>(f);
auto f_path = std::get<1>(f);
ui::Image thumb = ui::Canvas::I->thumbnail_read(f_path);
if (thumb.width == 0 || thumb.height == 0)
continue;
auto node = new NodeDialogBrowseItem;
node->m_manager = m_manager;
node->init();
node->m_text->set_text(n.c_str());
node->m_path = search_path + "/" + n;
node->m_file_name = n;
node->m_text->set_text(f_name.c_str());
node->m_path = f_path;
node->m_file_name = f_name;
node->on_selected = [&](NodeDialogBrowseItem* target) {
if (target == current)
return;

View File

@@ -39,7 +39,7 @@ public:
std::string selected_path;
std::string selected_file;
std::string selected_name;
std::string search_path;
std::vector<std::string> search_paths;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;