feat: add FTP and SFTP upload support
This commit is contained in:
+33
-11
@@ -15,6 +15,7 @@ extern void nativeOverlayConfirm(int x, int y, int w, int h, const char *annotat
|
||||
extern void nativeOverlayCopy(int x, int y, int w, int h, const char *annotationsJSON);
|
||||
extern void nativeOverlaySave(int x, int y, int w, int h, const char *annotationsJSON, const char *dir);
|
||||
extern void nativeOverlaySaveRemote(int x, int y, int w, int h, const char *annotationsJSON);
|
||||
extern void nativeOverlayUploadFTP(int x, int y, int w, int h, const char *annotationsJSON);
|
||||
extern void nativeOverlaySummarize(int x, int y, int w, int h, const char *annotationsJSON);
|
||||
extern void nativeOverlayOCR(int x, int y, int w, int h, const char *annotationsJSON);
|
||||
extern void nativeOverlayCancel(void);
|
||||
@@ -150,6 +151,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
@property(strong) NSButton *clipboardButton;
|
||||
@property(strong) NSButton *saveButton;
|
||||
@property(strong) NSButton *saveRemoteButton;
|
||||
@property(strong) NSButton *ftpButton;
|
||||
@property(strong) NSButton *ocrButton;
|
||||
@property(strong) NSButton *summaryButton;
|
||||
@property(strong) NSButton *uploadButton;
|
||||
@@ -181,6 +183,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
- (void)copySelection;
|
||||
- (void)saveSelection;
|
||||
- (void)saveRemoteSelection;
|
||||
- (void)uploadFTPSelection;
|
||||
- (void)ocrSelection;
|
||||
- (void)summarizeSelection;
|
||||
- (void)cancelSelection;
|
||||
@@ -222,6 +225,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
_clipboardButton = [SnipHoverButton buttonWithTitle:@"" target:self action:@selector(copySelection)];
|
||||
_saveButton = [SnipHoverButton buttonWithTitle:@"" target:self action:@selector(saveSelection)];
|
||||
_saveRemoteButton = [SnipHoverButton buttonWithTitle:@"" target:self action:@selector(saveRemoteSelection)];
|
||||
_ftpButton = [SnipHoverButton buttonWithTitle:@"" target:self action:@selector(uploadFTPSelection)];
|
||||
_ocrButton = [SnipHoverButton buttonWithTitle:@"" target:self action:@selector(ocrSelection)];
|
||||
_summaryButton = [SnipHoverButton buttonWithTitle:@"" target:self action:@selector(summarizeSelection)];
|
||||
_uploadButton = [SnipHoverButton buttonWithTitle:@"" target:self action:@selector(confirmSelection)];
|
||||
@@ -230,10 +234,11 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
[_cancelButton setToolTip:@"取消截图"];
|
||||
[_clipboardButton setToolTip:@"复制图片"];
|
||||
[_saveButton setToolTip:@"保存本地"];
|
||||
[_saveRemoteButton setToolTip:@"保存远端"];
|
||||
[_saveRemoteButton setToolTip:@"上传 SSH/SCP"];
|
||||
[_ftpButton setToolTip:@"上传 FTP/SFTP"];
|
||||
[_ocrButton setToolTip:@"提取文字"];
|
||||
[_summaryButton setToolTip:@"复制总结"];
|
||||
[_uploadButton setToolTip:@"上传云端"];
|
||||
[_uploadButton setToolTip:@"上传 S3"];
|
||||
_penButton = [NSButton buttonWithTitle:@"" target:self action:@selector(selectPen)];
|
||||
_rectButton = [NSButton buttonWithTitle:@"" target:self action:@selector(selectRect)];
|
||||
_ellipseButton = [NSButton buttonWithTitle:@"" target:self action:@selector(selectEllipse)];
|
||||
@@ -257,10 +262,10 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
// Add the action toolbar background BEFORE the buttons so it sits
|
||||
// behind them in the view hierarchy (AppKit z-order = subview order).
|
||||
[self addSubview:_actionToolbarBg];
|
||||
for (NSView *view in @[_cancelButton, _clipboardButton, _saveButton, _saveRemoteButton, _ocrButton, _summaryButton, _uploadButton, _penButton, _rectButton, _ellipseButton, _textButton, _undoButton, _toolSettingsView, _sizeLabel, _hintLabel]) {
|
||||
for (NSView *view in @[_cancelButton, _clipboardButton, _saveButton, _saveRemoteButton, _ftpButton, _ocrButton, _summaryButton, _uploadButton, _penButton, _rectButton, _ellipseButton, _textButton, _undoButton, _toolSettingsView, _sizeLabel, _hintLabel]) {
|
||||
[self addSubview:view];
|
||||
}
|
||||
for (NSView *view in @[_cancelButton, _clipboardButton, _saveButton, _saveRemoteButton, _ocrButton, _summaryButton, _uploadButton, _penButton, _rectButton, _ellipseButton, _textButton, _undoButton, _toolSettingsView, _actionToolbarBg]) {
|
||||
for (NSView *view in @[_cancelButton, _clipboardButton, _saveButton, _saveRemoteButton, _ftpButton, _ocrButton, _summaryButton, _uploadButton, _penButton, _rectButton, _ellipseButton, _textButton, _undoButton, _toolSettingsView, _actionToolbarBg]) {
|
||||
[view setHidden:YES];
|
||||
}
|
||||
[_sizeLabel setHidden:YES];
|
||||
@@ -323,7 +328,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
}
|
||||
|
||||
- (void)styleControls {
|
||||
// Cancel / Copy / Save / Save-remote / OCR / Summary / Upload — square icon buttons
|
||||
// Cancel / Copy / Save / SSH / FTP / OCR / Summary / S3 — square icon buttons
|
||||
// rendered from the user-supplied SVG assets. All actions default to white
|
||||
// and animate to a per-action accent color on hover (cancel = red,
|
||||
// others = blue). The base "white default" replaces the previous blue
|
||||
@@ -334,6 +339,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
// save-remote.svg — provided by the user; its content is the same arrow
|
||||
// icon as the previous upload, so we reuse it verbatim here.
|
||||
NSImage *saveRemoteIcon = [self iconFromSVG:@"<svg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'><path d='M481.749333 353.792c16.682667-16.64 43.690667-16.64 60.373334 0l120.917333 120.832 3.541333 4.010667a42.666667 42.666667 0 0 1-63.872 56.32L554.666667 486.954667V896a42.666667 42.666667 0 0 1-85.333334 0v-409.173333l-48.170666 48.128a42.666667 42.666667 0 0 1-60.330667 0l-3.541333-4.010667a42.666667 42.666667 0 0 1 3.541333-56.32zM512 85.333333c122.538667 0 227.84 73.813333 273.92 179.370667A213.333333 213.333333 0 0 1 725.333333 682.666667a42.666667 42.666667 0 0 1-4.992-85.034667L725.333333 597.333333a128 128 0 0 0 36.394667-250.794666l-38.144-11.264-15.914667-36.437334a213.376 213.376 0 0 0-407.296 58.026667l-7.381333 58.368-57.173333 13.824A85.418667 85.418667 0 0 0 256 597.333333h42.666667a42.666667 42.666667 0 0 1 0 85.333334H256a170.666667 170.666667 0 0 1-40.277333-336.554667A298.709333 298.709333 0 0 1 512 85.333333z' fill='white'/></svg>"];
|
||||
NSImage *ftpIcon = [self iconFromSVG:@"<svg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'><path d='M128 128h768v256H128V128zm64 64v128h640V192H192zm64 48h64v32h-64v-32zM128 448h416v64H192v192h352v64H128V448zm560-32 160 160-45.248 45.248L720 538.496V832h-64V538.496l-82.752 82.752L528 576l160-160z' fill='white'/></svg>"];
|
||||
NSImage *ocrIcon = [self iconFromSVG:@"<svg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'><path d='M192 160h192v64H256v128h-64V160zM640 160h192v192h-64V224H640v-64zM256 672v128h128v64H192V672h64zM832 672v192H640v-64h128V672h64zM469.333333 288h85.333334l170.666666 448h-78.933333l-39.253333-106.666667H416.853333L377.6 736H298.666667l170.666666-448zM439.466667 565.333333h144.896L512 368.981333 439.466667 565.333333z' fill='white'/></svg>"];
|
||||
NSImage *summaryIcon = [self iconFromSVG:@"<svg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'><path d='M256 128h448l192 192v576H256V128z m64 64v640h512V352H672V192H320z m416 45.248V288h50.752L736 237.248zM384 448h384v64H384v-64z m0 128h384v64H384v-64z m0 128h256v64H384v-64zM192 256v704h512v64H128V256h64z' fill='white'/></svg>"];
|
||||
// upload.svg — newly replaced "send/cloud" icon supplied by the user.
|
||||
@@ -343,6 +349,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
[self styleIconButton:_clipboardButton image:copyIcon];
|
||||
[self styleIconButton:_saveButton image:saveIcon];
|
||||
[self styleIconButton:_saveRemoteButton image:saveRemoteIcon];
|
||||
[self styleIconButton:_ftpButton image:ftpIcon];
|
||||
[self styleIconButton:_ocrButton image:ocrIcon];
|
||||
[self styleIconButton:_summaryButton image:summaryIcon];
|
||||
[self styleIconButton:_uploadButton image:uploadIcon];
|
||||
@@ -357,6 +364,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
SnipHoverButton *clipboardHB = (SnipHoverButton *)_clipboardButton;
|
||||
SnipHoverButton *saveHB = (SnipHoverButton *)_saveButton;
|
||||
SnipHoverButton *saveRemoteHB = (SnipHoverButton *)_saveRemoteButton;
|
||||
SnipHoverButton *ftpHB = (SnipHoverButton *)_ftpButton;
|
||||
SnipHoverButton *ocrHB = (SnipHoverButton *)_ocrButton;
|
||||
SnipHoverButton *summaryHB = (SnipHoverButton *)_summaryButton;
|
||||
SnipHoverButton *uploadHB = (SnipHoverButton *)_uploadButton;
|
||||
@@ -364,6 +372,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
clipboardHB.baseColor = baseWhite; clipboardHB.hoverColor = hoverBlue;
|
||||
saveHB.baseColor = baseWhite; saveHB.hoverColor = hoverBlue;
|
||||
saveRemoteHB.baseColor = baseWhite; saveRemoteHB.hoverColor = hoverBlue;
|
||||
ftpHB.baseColor = baseWhite; ftpHB.hoverColor = hoverBlue;
|
||||
ocrHB.baseColor = baseWhite; ocrHB.hoverColor = hoverBlue;
|
||||
summaryHB.baseColor = baseWhite; summaryHB.hoverColor = hoverBlue;
|
||||
uploadHB.baseColor = baseWhite; uploadHB.hoverColor = hoverBlue;
|
||||
@@ -921,6 +930,7 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
[_clipboardButton setHidden:!visible];
|
||||
[_saveButton setHidden:!visible];
|
||||
[_saveRemoteButton setHidden:!visible];
|
||||
[_ftpButton setHidden:!visible];
|
||||
[_ocrButton setHidden:!visible];
|
||||
[_summaryButton setHidden:!visible];
|
||||
[_uploadButton setHidden:!visible];
|
||||
@@ -941,12 +951,12 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
[_sizeLabel setStringValue:[NSString stringWithFormat:@"%.0f × %.0f", _selection.size.width, _selection.size.height]];
|
||||
[_sizeLabel setFrame:NSMakeRect(_selection.origin.x, MAX(0, _selection.origin.y - 26), 110, 22)];
|
||||
|
||||
// Action toolbar layout — 7 icon buttons, each 28x28, separated by 8px,
|
||||
// with 4px outer padding. Total = 7*28 + 6*8 + 2*4 = 252px wide.
|
||||
// Action toolbar layout — 8 icon buttons, each 28x28, separated by 8px,
|
||||
// with 4px outer padding. Total = 8*28 + 7*8 + 2*4 = 288px wide.
|
||||
CGFloat actionBtnSize = 28;
|
||||
CGFloat actionGap = 8;
|
||||
CGFloat actionPad = 4;
|
||||
NSInteger actionCount = 7;
|
||||
NSInteger actionCount = 8;
|
||||
CGFloat toolbarW = actionPad * 2 + actionBtnSize * actionCount + actionGap * (actionCount - 1);
|
||||
CGFloat toolbarH = 40;
|
||||
CGFloat x = _selection.origin.x + _selection.size.width - toolbarW;
|
||||
@@ -964,9 +974,10 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
[_clipboardButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 1, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_saveButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 2, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_saveRemoteButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 3, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_ocrButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 4, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_summaryButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 5, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_uploadButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 6, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_ftpButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 4, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_ocrButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 5, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_summaryButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 6, btnY, actionBtnSize, actionBtnSize)];
|
||||
[_uploadButton setFrame:NSMakeRect(baseX + (actionBtnSize + actionGap) * 7, btnY, actionBtnSize, actionBtnSize)];
|
||||
|
||||
// Mark toolbar sits to the LEFT of the action toolbar (same row) with an
|
||||
// 8px gap between the two groups, so they never overlap on tiny selections.
|
||||
@@ -1351,6 +1362,17 @@ static id nativeOverlayKeyMonitor = nil;
|
||||
nativeOverlaySaveRemote((int)llround(r.origin.x), (int)llround(r.origin.y), (int)llround(r.size.width), (int)llround(r.size.height), [json UTF8String]);
|
||||
}
|
||||
|
||||
// `uploadFTPSelection` dispatches the dedicated FTP/SFTP upload action.
|
||||
- (void)uploadFTPSelection {
|
||||
if (!_hasSelection) {
|
||||
return;
|
||||
}
|
||||
NSRect r = [self globalRectForSelection:_selection];
|
||||
NSString *json = [self annotationsJSON];
|
||||
[self closeOverlayWindow];
|
||||
nativeOverlayUploadFTP((int)llround(r.origin.x), (int)llround(r.origin.y), (int)llround(r.size.width), (int)llround(r.size.height), [json UTF8String]);
|
||||
}
|
||||
|
||||
// `ocrSelection` sends the screenshot to the configured OCR provider and
|
||||
// copies the extracted text.
|
||||
- (void)ocrSelection {
|
||||
|
||||
Reference in New Issue
Block a user