Skip to content

Commit

Permalink
Show progress icon for uploads.
Browse files Browse the repository at this point in the history
  • Loading branch information
dkocher committed Nov 26, 2024
1 parent 501923f commit 82e4404
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,33 @@
import ch.cyberduck.binding.foundation.NSProgress;
import ch.cyberduck.binding.foundation.NSURL;
import ch.cyberduck.core.Local;
import ch.cyberduck.core.transfer.Transfer;
import ch.cyberduck.core.transfer.TransferProgress;
import ch.cyberduck.core.transfer.TransferStatus;

public class FinderProgressIconService implements IconService {

@Override
public Icon get(final Local file) {
return new FinderProgressIcon(file);
public Icon get(final Transfer.Type type, final Local file) {
return new FinderProgressIcon(type, file);
}

private static final class FinderProgressIcon implements Icon {
private final NSProgress progress;

public FinderProgressIcon(final Local file) {
public FinderProgressIcon(final Transfer.Type type, final Local file) {
progress = NSProgress.discreteProgressWithTotalUnitCount(0L);
progress.setKind(NSProgress.NSProgressKindFile);
progress.setCancellable(false);
progress.setPausable(false);
progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading);
switch(type) {
case download:
progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading);
break;
case upload:
progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindUploading);
break;
}
progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute()));
progress.publish();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import ch.cyberduck.core.Local;
import ch.cyberduck.core.preferences.PreferencesFactory;
import ch.cyberduck.core.resources.IconCacheFactory;
import ch.cyberduck.core.transfer.Transfer;
import ch.cyberduck.core.transfer.TransferProgress;
import ch.cyberduck.core.unicode.NFDNormalizer;

Expand All @@ -33,30 +34,34 @@ public final class WorkspaceIconService implements IconService {
private static final NSWorkspace workspace = NSWorkspace.sharedWorkspace();

@Override
public Icon get(final Local file) {
return new Icon() {
// An integer between 0 and 9
private int step = 0;
public Icon get(final Transfer.Type type, final Local file) {
switch(type) {
case download:
return new Icon() {
// An integer between 0 and 9
private int step = 0;

@Override
public boolean update(final TransferProgress progress) {
if(progress.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) {
final int fraction = new BigDecimal(progress.getTransferred()).divide(new BigDecimal(progress.getSize()), 1, RoundingMode.DOWN).multiply(BigDecimal.TEN).intValue();
if(fraction >= step) {
// Another 10 percent of the file has been transferred
return WorkspaceIconService.update(file, IconCacheFactory.<NSImage>get().iconNamed(String.format("download%d.icns", step = fraction)));
@Override
public boolean update(final TransferProgress progress) {
if(progress.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) {
final int fraction = new BigDecimal(progress.getTransferred()).divide(new BigDecimal(progress.getSize()), 1, RoundingMode.DOWN).multiply(BigDecimal.TEN).intValue();
if(fraction >= step) {
// Another 10 percent of the file has been transferred
return WorkspaceIconService.update(file, IconCacheFactory.<NSImage>get().iconNamed(String.format("download%d.icns", step = fraction)));
}
return false;
}
return false;
}
return false;
}
return false;
}

@Override
public boolean remove() {
// The Finder will display the default icon for this file type
return WorkspaceIconService.update(file, null);
}
};
@Override
public boolean remove() {
// The Finder will display the default icon for this file type
return WorkspaceIconService.update(file, null);
}
};
}
return disabled;
}

public static boolean update(final Local file, final NSImage icon) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,12 @@
*/

import ch.cyberduck.core.Local;
import ch.cyberduck.core.transfer.TransferProgress;
import ch.cyberduck.core.transfer.Transfer;

public final class DisabledIconService implements IconService {

private static final Icon disabled = new Icon() {
@Override
public boolean update(final TransferProgress progress) {
return false;
}

@Override
public boolean remove() {
return false;
}
};

@Override
public Icon get(final Local file) {
public Icon get(final Transfer.Type type, final Local file) {
return disabled;
}
}
15 changes: 14 additions & 1 deletion core/src/main/java/ch/cyberduck/core/local/IconService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,30 @@
*/

import ch.cyberduck.core.Local;
import ch.cyberduck.core.transfer.Transfer;
import ch.cyberduck.core.transfer.TransferProgress;

public interface IconService {

Icon disabled = new Icon() {
@Override
public boolean update(final TransferProgress progress) {
return false;
}

@Override
public boolean remove() {
return false;
}
};

/**
* Get icon updater to track progress
*
* @param file Local file
* @return Updater to send continious progress updates to
*/
Icon get(Local file);
Icon get(Transfer.Type type, Local file);

interface Icon {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import ch.cyberduck.core.Factory;
import ch.cyberduck.core.Local;
import ch.cyberduck.core.transfer.Transfer;

public class IconServiceFactory extends Factory<IconService> {

Expand All @@ -31,7 +32,7 @@ public static IconService get() {
return new IconServiceFactory().create();
}

public static IconService.Icon iconFor(final Local file) {
return get().get(file);
public static IconService.Icon iconFor(final Transfer.Type type, final Local file) {
return get().get(type, file);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
import ch.cyberduck.core.io.BandwidthThrottle;
import ch.cyberduck.core.io.StreamListener;
import ch.cyberduck.core.local.DefaultLocalDirectoryFeature;
import ch.cyberduck.core.local.IconService;
import ch.cyberduck.core.local.IconServiceFactory;
import ch.cyberduck.core.local.LocalSymlinkFactory;
import ch.cyberduck.core.local.features.Symlink;
import ch.cyberduck.core.preferences.PreferencesFactory;
Expand All @@ -39,7 +37,6 @@
import ch.cyberduck.core.transfer.download.CompareFilter;
import ch.cyberduck.core.transfer.download.DownloadFilterOptions;
import ch.cyberduck.core.transfer.download.DownloadRegexPriorityComparator;
import ch.cyberduck.core.transfer.download.IconServiceStreamListener;
import ch.cyberduck.core.transfer.download.OverwriteFilter;
import ch.cyberduck.core.transfer.download.RenameExistingFilter;
import ch.cyberduck.core.transfer.download.RenameFilter;
Expand Down Expand Up @@ -304,13 +301,7 @@ public void transfer(final Session<?> source, final Session<?> destination, fina
}
// Transfer
final Download download = source.getFeature(Download.class);
final IconService.Icon icon = IconServiceFactory.iconFor(segment.isSegment() ? folder : local);
download.download(file, local, bandwidth, this.options.icon ?
new IconServiceStreamListener(this, icon, listener) : listener, segment, prompt);
// Remove custom icon if complete
if(segment.isComplete()) {
icon.remove();
}
download.download(file, local, bandwidth, listener, segment, prompt);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
import ch.cyberduck.core.exception.TransferCanceledException;
import ch.cyberduck.core.exception.TransferStatusCanceledException;
import ch.cyberduck.core.io.StreamListener;
import ch.cyberduck.core.local.IconService;
import ch.cyberduck.core.local.IconServiceFactory;
import ch.cyberduck.core.notification.NotificationService;
import ch.cyberduck.core.preferences.HostPreferences;
import ch.cyberduck.core.preferences.PreferencesFactory;
import ch.cyberduck.core.threading.TransferBackgroundActionState;
import ch.cyberduck.core.transfer.SynchronizingTransferErrorCallback;
Expand All @@ -38,6 +41,7 @@
import ch.cyberduck.core.transfer.TransferSpeedometer;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.core.transfer.TransferStreamListener;
import ch.cyberduck.core.transfer.download.IconServiceStreamListener;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.concurrent.ConcurrentUtils;
Expand Down Expand Up @@ -380,12 +384,25 @@ private void transferSegment(final TransferStatus segment) throws BackgroundExce
log.debug("Transfer item {} with status {}", item, segment);
final Session<?> s = borrow(Connection.source);
final Session<?> d = borrow(Connection.destination);
final BytecountStreamListener counter = new TransferStreamListener(transfer, stream);
final IconService.Icon icon;
if(new HostPreferences(s.getHost()).getBoolean(String.format("queue.%s.icon.update", transfer.getType().name()))) {
icon = IconServiceFactory.iconFor(transfer.getType(),
segment.getRename().local != null ? segment.isSegment() ? segment.getRename().local.getParent() : segment.getRename().local : item.local);
}
else {
icon = IconService.disabled;
}
final BytecountStreamListener counter = new TransferStreamListener(transfer,
new IconServiceStreamListener(transfer, icon, stream));
try {
transfer.transfer(s, d,
segment.getRename().remote != null ? segment.getRename().remote : item.remote,
segment.getRename().local != null ? segment.getRename().local : item.local,
options, segment, connect, progress, counter);
if(transfer.isComplete()) {
// Remove custom icon if complete
icon.remove();
}
}
catch(BackgroundException e) {
release(s, Connection.source, e);
Expand Down
2 changes: 1 addition & 1 deletion defaults/src/main/resources/default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ queue.connections.limit.default=5
queue.connections.limit.ftp=1
# Auto determine number of connections
queue.connections.options=0,1,2,3,4,5,10,15,20

queue.upload.icon.update=true
# While downloading, update the icon of the downloaded file as a progress indicator
queue.download.icon.update=true
queue.download.icon.threshold=5242880
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
import ch.cyberduck.core.local.DefaultLocalDirectoryFeature;
import ch.cyberduck.core.local.FileDescriptor;
import ch.cyberduck.core.local.FileDescriptorFactory;
import ch.cyberduck.core.local.IconServiceFactory;
import ch.cyberduck.core.local.LocalTouchFactory;
import ch.cyberduck.core.local.WorkspaceIconService;
import ch.cyberduck.core.pasteboard.PathPasteboard;
import ch.cyberduck.core.pasteboard.PathPasteboardFactory;
import ch.cyberduck.core.preferences.Preferences;
Expand All @@ -69,7 +69,6 @@
import ch.cyberduck.core.transfer.DownloadTransfer;
import ch.cyberduck.core.transfer.Transfer;
import ch.cyberduck.core.transfer.TransferItem;
import ch.cyberduck.core.transfer.TransferProgress;
import ch.cyberduck.core.transfer.UploadTransfer;
import ch.cyberduck.core.transfer.download.DownloadFilterOptions;
import ch.cyberduck.ui.browser.BrowserColumn;
Expand Down Expand Up @@ -390,7 +389,7 @@ public boolean acceptDrop(final NSTableView view, final Path destination, final
for(int i = 0; i < elements.count().intValue(); i++) {
final Local local = LocalFactory.get(elements.objectAtIndex(new NSUInteger(i)).toString());
roots.add(new TransferItem(new Path(destination, local.getName(),
local.isDirectory() ? EnumSet.of(Path.Type.directory) : EnumSet.of(Path.Type.file)), local));
local.isDirectory() ? EnumSet.of(Path.Type.directory) : EnumSet.of(Path.Type.file)), local));
}
controller.transfer(new UploadTransfer(controller.getSession().getHost(), roots));
return true;
Expand Down Expand Up @@ -648,7 +647,7 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) {
try {
LocalTouchFactory.get().touch(file);
if(options.icon) {
IconServiceFactory.iconFor(file).update(new TransferProgress(0L, 0L));
WorkspaceIconService.update(file, IconCacheFactory.<NSImage>get().iconNamed(String.format("download%d.icns", 0)));
}
}
catch(AccessDeniedException e) {
Expand Down Expand Up @@ -678,7 +677,7 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) {
}
else {
final Transfer transfer = new DownloadTransfer(controller.getSession().getHost(), downloads)
.withOptions(options);
.withOptions(options);
controller.transfer(transfer, Collections.emptyList());
}
pasteboard.clear();
Expand Down

0 comments on commit 82e4404

Please sign in to comment.