├── .idea ├── .name ├── .gitignore ├── codeStyles │ └── codeStyleConfig.xml ├── vcs.xml ├── dictionaries │ └── alexey.xml ├── runConfigurations │ ├── LocalUiLauncher_nl_NL.xml │ ├── LocalUiLauncher_ru_RU.xml │ ├── LocalUiLauncher_zh_HANS.xml │ ├── LocalUiLauncher.xml │ ├── LocalCliLauncher.xml │ └── All_tests.xml ├── gradle.xml └── misc.xml ├── src ├── main │ ├── resources │ │ ├── Icon1024.png │ │ ├── info-icon.png │ │ ├── info-symbol.png │ │ ├── warning-icon.png │ │ ├── folder-structure-hint.png │ │ ├── LoginDialog.fxml │ │ ├── SupportPane.fxml │ │ ├── PreferencePatternEditor.fxml │ │ ├── log4j2.yaml │ │ ├── MainScreen.fxml │ │ ├── upgradeNotificationDialog.fxml │ │ ├── style.css │ │ ├── FailureLog.fxml │ │ ├── AboutDialog.fxml │ │ ├── UploaderStrategyChoicePanel.fxml │ │ ├── FolderSelector.fxml │ │ ├── UploadPane.fxml │ │ ├── ProgressBox.fxml │ │ ├── PreferencesDialog.fxml │ │ └── i18n │ │ │ ├── Resources_zh_Hans.properties │ │ │ └── Resources_zh_Hant.properties │ ├── packaging-resources │ │ ├── Icon1024.png │ │ ├── Icon1024.xcf │ │ ├── linux │ │ │ ├── JiottyPhotosUploader.png │ │ │ └── JiottyPhotosUploader.desktop │ │ ├── windows │ │ │ └── Jiotty Photos Uploader.ico │ │ └── macOS │ │ │ ├── out │ │ │ ├── Jiotty Photos Uploader.icns │ │ │ ├── Jiotty Photos Uploader-volume.icns │ │ │ └── Info.plist │ │ │ ├── entitlements.plist │ │ │ └── createicns.sh │ └── java │ │ ├── net │ │ └── yudichev │ │ │ └── googlephotosupload │ │ │ ├── ui │ │ │ ├── AnimatedNode.java │ │ │ ├── LoginDialogFxController.java │ │ │ ├── ProgressStatusBar.java │ │ │ ├── FxmlContainer.java │ │ │ ├── MainScreenController.java │ │ │ ├── FxmlContainerFactory.java │ │ │ ├── Launcher.java │ │ │ ├── ProgressStatusBarFactory.java │ │ │ ├── ProgressValueUpdaterFactory.java │ │ │ ├── Dialog.java │ │ │ ├── ProgressBox.java │ │ │ ├── FolderSelectorController.java │ │ │ ├── UpgradeNotificationDialogController.java │ │ │ ├── DialogFactory.java │ │ │ ├── UploadPaneController.java │ │ │ ├── ProgressValueUpdater.java │ │ │ ├── BaseJavafxApplicationResources.java │ │ │ ├── PlatformSpecificMenu.java │ │ │ ├── UploaderStrategyChoicePanelController.java │ │ │ ├── Bindings.java │ │ │ ├── LoginDialogControllerImpl.java │ │ │ ├── UploaderStrategyChoicePanelControllerProvider.java │ │ │ ├── UiAuthorizationBrowserModule.java │ │ │ ├── FatalStartupError.java │ │ │ ├── UiProgressStatusFactory.java │ │ │ ├── SupportPaneController.java │ │ │ ├── FxmlContainerFactoryImpl.java │ │ │ ├── SepiaToneEffectAnimatedNode.java │ │ │ ├── OperatingSystemDetection.java │ │ │ ├── AboutDialogFxController.java │ │ │ ├── SingleInstanceCheck.java │ │ │ ├── DialogImpl.java │ │ │ ├── ProgressStatusBarImpl.java │ │ │ ├── UploaderStrategyChoicePanelControllerImpl.java │ │ │ ├── DefaultPlatformSpecificMenu.java │ │ │ ├── MacPlatformSpecificMenu.java │ │ │ ├── UiMain.java │ │ │ ├── UiAuthorizationBrowser.java │ │ │ ├── UpgradeNotificationDialogControllerImpl.java │ │ │ ├── UserInterface.java │ │ │ ├── PreferencePatternEditorController.java │ │ │ ├── ThrottlingProgressStatus.java │ │ │ ├── UiModule.java │ │ │ ├── FailureLogFxController.java │ │ │ ├── FolderSelectorControllerImpl.java │ │ │ ├── PreferencesDialogController.java │ │ │ └── ProgressBoxFxController.java │ │ │ ├── core │ │ │ ├── StateSaverFactory.java │ │ │ ├── AddToAlbumMethod.java │ │ │ ├── Restarter.java │ │ │ ├── UploadStateManager.java │ │ │ ├── StateSaver.java │ │ │ ├── FatalUserCorrectableRemoteApiExceptionHandler.java │ │ │ ├── ProgressStatusFactory.java │ │ │ ├── PreferencesManager.java │ │ │ ├── DirectoryStructureSupplier.java │ │ │ ├── Uploader.java │ │ │ ├── CloudAlbumsProvider.java │ │ │ ├── BackingOffRemoteApiExceptionHandler.java │ │ │ ├── CloudOperationHelper.java │ │ │ ├── BaseKeyedError.java │ │ │ ├── BaseRetryableFailure.java │ │ │ ├── BuildVersion.java │ │ │ ├── BasePathState.java │ │ │ ├── AppGlobals.java │ │ │ ├── BasePathMediaItemOrError.java │ │ │ ├── AlbumManager.java │ │ │ ├── Bindings.java │ │ │ ├── BaseUploadState.java │ │ │ ├── RootDirProvider.java │ │ │ ├── ProgressStatus.java │ │ │ ├── GooglePhotosUploader.java │ │ │ ├── SynchronizedBackOff.java │ │ │ ├── AddToAlbumStrategy.java │ │ │ ├── StateSaverImpl.java │ │ │ ├── BaseItemState.java │ │ │ ├── BackOffProvider.java │ │ │ ├── UploadStateManagerImpl.java │ │ │ ├── AddToAlbumWhileCreatingStrategy.java │ │ │ ├── FatalUserCorrectableRemoteApiExceptionHandlerImpl.java │ │ │ ├── RestarterImpl.java │ │ │ ├── BackpressuredExecutorServiceProvider.java │ │ │ ├── CloudOperationHelperImpl.java │ │ │ ├── ResourceBundleModule.java │ │ │ ├── BackingOffRemoteApiExceptionHandlerImpl.java │ │ │ ├── DependenciesModule.java │ │ │ ├── UploadPhotosModule.java │ │ │ ├── SelectingAddToAlbumStrategy.java │ │ │ ├── CloudAlbumsProviderImpl.java │ │ │ └── UploaderImpl.java │ │ │ └── cli │ │ │ ├── PreferencesManagerImpl.java │ │ │ ├── CliOptions.java │ │ │ ├── CliModule.java │ │ │ ├── CliStarter.java │ │ │ ├── CliMain.java │ │ │ └── LoggingProgressStatusFactory.java │ │ └── module-info.java.disabled └── test │ ├── java │ └── net │ │ └── yudichev │ │ └── googlephotosupload │ │ └── core │ │ ├── LocalCliLauncher.java │ │ ├── LocalUiLauncher.java │ │ ├── BaseMediaItemContents.java │ │ ├── EmptyOptional.java │ │ ├── MockGooglePhotosModule.java │ │ ├── InvalidMediaItemFatalUserCorrectableRemoteApiExceptionHandlerTest.java │ │ ├── TestTimeModule.java │ │ ├── RecordingProgressStatusFactory.java │ │ ├── OptionalMatchers.java │ │ ├── PresentOptional.java │ │ ├── IntegrationTestUploadStarterModule.java │ │ ├── IntegrationTestUploadStarter.java │ │ └── PreferencesTest.java │ └── resources │ └── log4j2-test.yaml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── .gitignore ├── README.md ├── .github └── workflows │ └── gradle.yml └── gradlew.bat /.idea/.name: -------------------------------------------------------------------------------- 1 | Jiotty Photos Uploader -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml 3 | /shelf/ -------------------------------------------------------------------------------- /src/main/resources/Icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/resources/Icon1024.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/info-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/resources/info-icon.png -------------------------------------------------------------------------------- /src/main/resources/info-symbol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/resources/info-symbol.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | */ 4 | 5 | rootProject.name = 'Jiotty Photos Uploader' 6 | -------------------------------------------------------------------------------- /src/main/resources/warning-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/resources/warning-icon.png -------------------------------------------------------------------------------- /src/main/packaging-resources/Icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/packaging-resources/Icon1024.png -------------------------------------------------------------------------------- /src/main/packaging-resources/Icon1024.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/packaging-resources/Icon1024.xcf -------------------------------------------------------------------------------- /src/main/resources/folder-structure-hint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/resources/folder-structure-hint.png -------------------------------------------------------------------------------- /src/main/packaging-resources/linux/JiottyPhotosUploader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/packaging-resources/linux/JiottyPhotosUploader.png -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /src/main/packaging-resources/windows/Jiotty Photos Uploader.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/packaging-resources/windows/Jiotty Photos Uploader.ico -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/AnimatedNode.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | interface AnimatedNode { 4 | void show(); 5 | 6 | void hide(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/packaging-resources/macOS/out/Jiotty Photos Uploader.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/packaging-resources/macOS/out/Jiotty Photos Uploader.icns -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/LoginDialogFxController.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | interface LoginDialogFxController { 4 | void load(String url); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/ProgressStatusBar.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | interface ProgressStatusBar extends ProgressValueUpdater, ProgressBox { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/FxmlContainer.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | interface FxmlContainer { 4 | T root(); 5 | 6 | T controller(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/MainScreenController.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | public interface MainScreenController { 4 | void toFolderSelectionMode(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/packaging-resources/macOS/out/Jiotty Photos Uploader-volume.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/jiotty-photos-uploader/master/src/main/packaging-resources/macOS/out/Jiotty Photos Uploader-volume.icns -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/FxmlContainerFactory.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | interface FxmlContainerFactory { 4 | FxmlContainer create(String fxmlResourcePath); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/StateSaverFactory.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | interface StateSaverFactory { 4 | StateSaver create(String name, Runnable saveAction); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/AddToAlbumMethod.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | public enum AddToAlbumMethod { 4 | WHILE_CREATING_ITEMS, 5 | AFTER_CREATING_ITEMS_SORTED 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/Restarter.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | public interface Restarter { 4 | void initiateLogoutAndRestart(); 5 | 6 | void initiateRestart(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/Launcher.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | public class Launcher { 4 | public static void main(String[] args) { 5 | UiMain.main(args); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/UploadStateManager.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | interface UploadStateManager { 4 | UploadState get(); 5 | 6 | void save(UploadState uploadState); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/StateSaver.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.common.lang.Closeable; 4 | 5 | interface StateSaver extends Closeable { 6 | void save(); 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | build/** 3 | out/** 4 | .gradle/** 5 | /.idea/libraries/** 6 | /.idea/compiler.xml 7 | /.idea/modules.xml 8 | /.idea/encodings.xml 9 | /.idea/workspace.xml 10 | /.idea/jarRepositories.xml 11 | /.idea/$PRODUCT_WORKSPACE_FILE$ 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Jiotty Photos Uploader is a simple desktop Google Photos media uploader that creates albums according to your directory structure and can resume failed uploads. See [Wiki](https://github.com/ylexus/jiotty-photos-uploader/wiki) for more information. 2 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/FatalUserCorrectableRemoteApiExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | interface FatalUserCorrectableRemoteApiExceptionHandler { 4 | boolean handle(String operationName, Throwable exception); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/ProgressStatusFactory.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.util.Optional; 4 | 5 | public interface ProgressStatusFactory { 6 | ProgressStatus create(String name, Optional totalCount); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/ProgressStatusBarFactory.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import java.util.Optional; 4 | 5 | interface ProgressStatusBarFactory { 6 | ProgressStatusBar create(String name, Optional totalCount); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/ProgressValueUpdaterFactory.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import java.util.Optional; 4 | 5 | interface ProgressValueUpdaterFactory { 6 | ProgressValueUpdater create(String name, Optional totalCount); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/Dialog.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import net.yudichev.jiotty.common.lang.Closeable; 4 | 5 | interface Dialog extends Closeable { 6 | void show(); 7 | 8 | T controller(); 9 | 10 | void sizeToScene(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/ProgressBox.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import javafx.scene.Node; 4 | import net.yudichev.jiotty.common.lang.Closeable; 5 | 6 | interface ProgressBox extends Closeable { 7 | Node node(); 8 | 9 | boolean hasFailures(); 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/yudichev/googlephotosupload/core/LocalCliLauncher.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.googlephotosupload.cli.CliMain; 4 | 5 | public class LocalCliLauncher { 6 | public static void main(String[] args) { 7 | CliMain.main(args); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/net/yudichev/googlephotosupload/core/LocalUiLauncher.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.googlephotosupload.ui.Launcher; 4 | 5 | public class LocalUiLauncher { 6 | public static void main(String[] args) { 7 | Launcher.main(args); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | #Mon Mar 30 20:08:07 BST 2020 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-all.zip 4 | distributionBase=GRADLE_USER_HOME 5 | distributionPath=wrapper/dists 6 | zipStorePath=wrapper/dists 7 | zipStoreBase=GRADLE_USER_HOME 8 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/PreferencesManager.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.util.function.Function; 4 | import java.util.function.Supplier; 5 | 6 | public interface PreferencesManager extends Supplier { 7 | void update(Function updater); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/FolderSelectorController.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import java.nio.file.Path; 4 | import java.util.function.BiConsumer; 5 | 6 | interface FolderSelectorController { 7 | void refresh(); 8 | 9 | void setFolderSelectedAction(BiConsumer folderSelectionListener); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/UpgradeNotificationDialogController.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import java.util.List; 4 | 5 | interface UpgradeNotificationDialogController { 6 | void initialise(List orderedNewerRevisions, Runnable dismissAction, Runnable ignoreVersionAction, Runnable dialogResizeAction); 7 | } 8 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Set up JDK 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 14.0.1 16 | - name: Build with Gradle 17 | run: ./gradlew test --no-daemon 18 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/DirectoryStructureSupplier.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.nio.file.Path; 4 | import java.util.List; 5 | import java.util.concurrent.CompletableFuture; 6 | 7 | interface DirectoryStructureSupplier { 8 | CompletableFuture> listAlbumDirectories(Path rootDir); 9 | } 10 | -------------------------------------------------------------------------------- /.idea/dictionaries/alexey.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | backoff 5 | backpressured 6 | googlephotosupload 7 | immutables 8 | jiotty 9 | picasa 10 | retryable 11 | yudichev 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/Uploader.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.nio.file.Path; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | public interface Uploader { 7 | CompletableFuture upload(Path rootDir, boolean resume); 8 | 9 | int numberOfUploadedItems(); 10 | 11 | void forgetUploadState(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/DialogFactory.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import com.google.inject.assistedinject.Assisted; 4 | import javafx.stage.Stage; 5 | 6 | import java.util.function.Consumer; 7 | 8 | interface DialogFactory { 9 | Dialog create(@Assisted("title") String title, @Assisted("fxmlPath") String fxmlPath, Consumer customizer); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/packaging-resources/linux/JiottyPhotosUploader.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Encoding=UTF-8 4 | Name=Jiotty Photos Uploader 5 | Comment=Upload your photos and movies into your Google Photos library and sort them into albums 6 | Exec=/opt/jiotty-photos-uploader/bin/JiottyPhotosUploader 7 | Icon=/opt/jiotty-photos-uploader/lib/JiottyPhotosUploader.png 8 | Categories=GTK;GNOME;Utility; 9 | Terminal=false -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/CloudAlbumsProvider.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.connector.google.photos.GooglePhotosAlbum; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.CompletableFuture; 8 | 9 | interface CloudAlbumsProvider { 10 | CompletableFuture>> listCloudAlbums(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/UploadPaneController.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import java.nio.file.Path; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | interface UploadPaneController { 7 | void addProgressBox(ProgressBox progressBox); 8 | 9 | void reset(); 10 | 11 | CompletableFuture startUpload(Path path, boolean resume); 12 | 13 | void stopUpload(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/BackingOffRemoteApiExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.util.Optional; 4 | 5 | interface BackingOffRemoteApiExceptionHandler { 6 | /** 7 | * @return backoff delay applied, in milliseconds, or 0, if no backoff delay was applied 8 | */ 9 | Optional handle(String operationName, Throwable exception); 10 | 11 | void reset(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/CloudOperationHelper.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.function.LongConsumer; 5 | import java.util.function.Supplier; 6 | 7 | interface CloudOperationHelper { 8 | CompletableFuture withBackOffAndRetry(String operationName, Supplier> action, LongConsumer backoffEventConsumer); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/BaseKeyedError.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.common.lang.PublicImmutablesStyle; 4 | import org.immutables.value.Value; 5 | import org.immutables.value.Value.Immutable; 6 | 7 | @Immutable 8 | @PublicImmutablesStyle 9 | interface BaseKeyedError { 10 | @Value.Parameter 11 | Object getKey(); 12 | 13 | @Value.Parameter 14 | String getError(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/ProgressValueUpdater.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import net.yudichev.googlephotosupload.core.KeyedError; 4 | 5 | import java.util.Collection; 6 | 7 | interface ProgressValueUpdater { 8 | void updateSuccess(int newValue); 9 | 10 | void addFailures(Collection failures); 11 | 12 | void completed(boolean success); 13 | 14 | void onBackoffDelay(long backoffDelayMs); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/BaseRetryableFailure.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.common.lang.PackagePrivateImmutablesStyle; 4 | import org.immutables.value.Value; 5 | 6 | import java.util.Optional; 7 | 8 | @Value.Immutable 9 | @PackagePrivateImmutablesStyle 10 | interface BaseRetryableFailure { 11 | @Value.Parameter 12 | Throwable exception(); 13 | 14 | @Value.Parameter 15 | Optional backoffDelayMs(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/BaseJavafxApplicationResources.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import javafx.application.HostServices; 4 | import javafx.stage.Stage; 5 | import net.yudichev.jiotty.common.lang.PackagePrivateImmutablesStyle; 6 | import org.immutables.value.Value.Immutable; 7 | 8 | @Immutable 9 | @PackagePrivateImmutablesStyle 10 | interface BaseJavafxApplicationResources { 11 | Stage primaryStage(); 12 | 13 | HostServices hostServices(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/BuildVersion.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.util.Optional; 4 | 5 | public final class BuildVersion { 6 | private static final String IMPLEMENTATION_VERSION = Optional 7 | .ofNullable(BuildVersion.class.getPackage().getImplementationVersion()) 8 | .orElse("0.DEV"); 9 | 10 | BuildVersion() { 11 | } 12 | 13 | public static String buildVersion() { 14 | return IMPLEMENTATION_VERSION; 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/BasePathState.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.common.lang.PackagePrivateImmutablesStyle; 4 | import net.yudichev.jiotty.common.lang.ResultOrFailure; 5 | import org.immutables.value.Value; 6 | 7 | import java.nio.file.Path; 8 | 9 | @Value.Immutable 10 | @PackagePrivateImmutablesStyle 11 | interface BasePathState { 12 | @Value.Parameter 13 | Path path(); 14 | 15 | @Value.Parameter 16 | ResultOrFailure state(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/AppGlobals.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import java.nio.file.Path; 4 | import java.nio.file.Paths; 5 | 6 | public final class AppGlobals { 7 | public static final String APP_TITLE = "Jiotty Photos Uploader"; 8 | public static final String APP_SETTINGS_DIR_NAME = "jiottyphotosuploader"; 9 | public static final Path APP_SETTINGS_DIR = Paths.get(System.getProperty("user.home"), "." + APP_SETTINGS_DIR_NAME); 10 | 11 | private AppGlobals() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.idea/runConfigurations/LocalUiLauncher_nl_NL.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/LocalUiLauncher_ru_RU.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/LocalUiLauncher_zh_HANS.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/BasePathMediaItemOrError.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.common.lang.PackagePrivateImmutablesStyle; 4 | import net.yudichev.jiotty.connector.google.photos.GoogleMediaItem; 5 | import org.immutables.value.Value; 6 | 7 | import java.nio.file.Path; 8 | 9 | @Value.Immutable 10 | @PackagePrivateImmutablesStyle 11 | interface BasePathMediaItemOrError { 12 | @Value.Parameter 13 | Path path(); 14 | 15 | @Value.Parameter 16 | GoogleMediaItem mediaItem(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/PlatformSpecificMenu.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import javafx.event.ActionEvent; 4 | import javafx.event.EventHandler; 5 | import javafx.scene.control.MenuBar; 6 | 7 | interface PlatformSpecificMenu { 8 | void initialize(MenuBar menuBar); 9 | 10 | void setOnExitAction(EventHandler onExitEventHandler); 11 | 12 | void setOnPreferencesAction(EventHandler onPreferencesEventHandler); 13 | 14 | void setOnAboutAction(EventHandler onAboutAction); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/AlbumManager.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.connector.google.photos.GooglePhotosAlbum; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.CompletableFuture; 8 | 9 | interface AlbumManager { 10 | CompletableFuture> listAlbumsByTitle(List albumDirectories, 11 | Map> cloudAlbumsByTitle); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/UploaderStrategyChoicePanelController.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import javafx.scene.Node; 4 | import net.yudichev.googlephotosupload.core.AddToAlbumMethod; 5 | import net.yudichev.jiotty.common.lang.Closeable; 6 | 7 | import java.util.function.Consumer; 8 | 9 | interface UploaderStrategyChoicePanelController { 10 | Node getRoot(); 11 | 12 | void setSelection(AddToAlbumMethod addToAlbumMethod); 13 | 14 | Closeable addSelectionChangeListener(Consumer selectionChangeHandler); 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/log4j2-test.yaml: -------------------------------------------------------------------------------- 1 | Configuration: 2 | name: Automator 3 | appenders: 4 | Console: 5 | name: STDOUT 6 | PatternLayout: 7 | Pattern: "%d{ISO8601}{GMT} %p [%t] %C{1.} %m%n" 8 | 9 | Loggers: 10 | logger: 11 | - name: net.yudichev.jiotty.connector.google.photos 12 | level: debug 13 | includeLocation: true 14 | - name: net.yudichev.googlephotosupload 15 | level: debug 16 | includeLocation: true 17 | Root: 18 | level: info 19 | includeLocation: true 20 | AppenderRef: 21 | - ref: STDOUT -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/Bindings.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import com.google.inject.BindingAnnotation; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.Target; 7 | 8 | import static java.lang.annotation.ElementType.*; 9 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 10 | 11 | final class Bindings { 12 | private Bindings() { 13 | } 14 | 15 | @BindingAnnotation 16 | @Target({FIELD, PARAMETER, METHOD}) 17 | @Retention(RUNTIME) 18 | @interface AuthBrowser { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/Bindings.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import com.google.inject.BindingAnnotation; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.Target; 7 | 8 | import static java.lang.annotation.ElementType.*; 9 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 10 | 11 | final class Bindings { 12 | private Bindings() { 13 | } 14 | 15 | @BindingAnnotation 16 | @Target({FIELD, PARAMETER, METHOD}) 17 | @Retention(RUNTIME) 18 | @interface Backpressured { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/BaseUploadState.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import net.yudichev.jiotty.common.lang.PackagePrivateImmutablesStyle; 6 | import org.immutables.value.Value; 7 | 8 | import java.util.Map; 9 | 10 | @Value.Immutable 11 | @PackagePrivateImmutablesStyle 12 | @JsonSerialize 13 | @JsonDeserialize 14 | interface BaseUploadState { 15 | @Value.Parameter 16 | Map uploadedMediaItemIdByAbsolutePath(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/RootDirProvider.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import org.apache.commons.cli.CommandLine; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Provider; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | 10 | final class RootDirProvider implements Provider { 11 | private final Path rootDir; 12 | 13 | @Inject 14 | RootDirProvider(CommandLine commandLine) { 15 | rootDir = Paths.get(commandLine.getOptionValue('r')); 16 | } 17 | 18 | @Override 19 | public Path get() { 20 | return rootDir; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/packaging-resources/macOS/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | com.apple.security.cs.allow-unsigned-executable-memory 8 | 9 | com.apple.security.cs.disable-executable-page-protection 10 | 11 | com.apple.security.cs.disable-library-validation 12 | 13 | com.apple.security.cs.allow-dyld-environment-variables 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/cli/PreferencesManagerImpl.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.cli; 2 | 3 | import net.yudichev.googlephotosupload.core.Preferences; 4 | import net.yudichev.googlephotosupload.core.PreferencesManager; 5 | 6 | import java.util.function.Function; 7 | 8 | final class PreferencesManagerImpl implements PreferencesManager { 9 | @Override 10 | public void update(Function updater) { 11 | } 12 | 13 | // TODO add taking preferences via command line 14 | @Override 15 | public Preferences get() { 16 | return Preferences.builder().build(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.idea/runConfigurations/LocalUiLauncher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/LoginDialogControllerImpl.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import javafx.scene.control.TextField; 4 | import javafx.scene.web.WebView; 5 | 6 | public final class LoginDialogControllerImpl implements LoginDialogFxController { 7 | public WebView webView; 8 | public TextField urlTextField; 9 | 10 | public void initialize() { 11 | webView.getEngine().locationProperty().addListener((observable, oldValue, newValue) -> urlTextField.setText(newValue)); 12 | } 13 | 14 | @Override 15 | public void load(String url) { 16 | webView.getEngine().load(url); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/ProgressStatus.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | public interface ProgressStatus { 4 | void updateSuccess(int newValue); 5 | 6 | void incrementSuccessBy(int increment); 7 | 8 | void onBackoffDelay(long backoffDelayMs); 9 | 10 | default void incrementSuccess() { 11 | incrementSuccessBy(1); 12 | } 13 | 14 | void close(boolean success); 15 | 16 | default void closeSuccessfully() { 17 | close(true); 18 | } 19 | 20 | default void closeUnsuccessfully() { 21 | close(false); 22 | } 23 | 24 | void addFailure(KeyedError keyedError); 25 | } 26 | -------------------------------------------------------------------------------- /.idea/runConfigurations/LocalCliLauncher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/resources/LoginDialog.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/GooglePhotosUploader.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.common.inject.LifecycleComponent; 4 | import net.yudichev.jiotty.connector.google.photos.GooglePhotosAlbum; 5 | 6 | import java.nio.file.Path; 7 | import java.util.List; 8 | import java.util.Optional; 9 | import java.util.concurrent.CompletableFuture; 10 | 11 | interface GooglePhotosUploader extends LifecycleComponent { 12 | CompletableFuture uploadDirectory(Optional googlePhotosAlbum, 13 | List files, 14 | ProgressStatus fileProgressStatus); 15 | 16 | void doNotResume(); 17 | 18 | void forgetUploadStateOnShutdown(); 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/net/yudichev/googlephotosupload/core/BaseMediaItemContents.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import net.yudichev.jiotty.common.lang.PackagePrivateImmutablesStyle; 6 | import org.immutables.value.Value; 7 | 8 | import java.time.Instant; 9 | 10 | @Value.Immutable 11 | @PackagePrivateImmutablesStyle 12 | @JsonSerialize 13 | @JsonDeserialize 14 | abstract class BaseMediaItemContents { 15 | @Value.Parameter 16 | public abstract Instant creationTime(); 17 | 18 | @Value.Parameter 19 | public abstract int contents(); 20 | 21 | public final String toMediaItemId() { 22 | return creationTime().toString() + '/' + contents(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/module-info.java.disabled: -------------------------------------------------------------------------------- 1 | module net.yudichev.googlephotosupload { 2 | requires com.google.guice; 3 | requires javax.inject; 4 | requires javafx.fxml; 5 | requires com.google.common; 6 | requires jiotty.common; 7 | requires javafx.web; 8 | requires com.google.guice.extensions.assistedinject; 9 | requires jiotty.connector.google.common; 10 | requires slf4j.api; 11 | requires jiotty.connector.google.photos; 12 | requires gax; 13 | requires jsr305; 14 | requires commons.cli; 15 | requires static org.immutables.value; 16 | requires com.google.api.client; 17 | requires com.fasterxml.jackson.databind; 18 | requires proto.google.common.protos; 19 | requires error.prone.annotations; 20 | requires jackson.annotations; 21 | requires org.apache.logging.log4j; 22 | } -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/cli/CliOptions.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.cli; 2 | 3 | import org.apache.commons.cli.Option; 4 | import org.apache.commons.cli.Options; 5 | 6 | public final class CliOptions { 7 | public static final Options OPTIONS = new Options() 8 | .addOption(Option.builder("r") 9 | .longOpt("root-dir") 10 | .hasArg() 11 | .argName("PATH") 12 | .desc("Path to root directory to scan") 13 | .required() 14 | .build()) 15 | .addOption(Option.builder("n") 16 | .longOpt("no-resume") 17 | .desc("Forget previous state and force re-uploading all files") 18 | .build()); 19 | 20 | private CliOptions() { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/ui/UploaderStrategyChoicePanelControllerProvider.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.ui; 2 | 3 | import javax.inject.Inject; 4 | import javax.inject.Provider; 5 | 6 | import static com.google.common.base.Preconditions.checkNotNull; 7 | 8 | final class UploaderStrategyChoicePanelControllerProvider implements Provider { 9 | private final FxmlContainerFactory fxmlContainerFactory; 10 | 11 | @Inject 12 | UploaderStrategyChoicePanelControllerProvider(FxmlContainerFactory fxmlContainerFactory) { 13 | this.fxmlContainerFactory = checkNotNull(fxmlContainerFactory); 14 | } 15 | 16 | @Override 17 | public UploaderStrategyChoicePanelController get() { 18 | return fxmlContainerFactory.create("UploaderStrategyChoicePanel.fxml").controller(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/SynchronizedBackOff.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import com.google.api.client.util.BackOff; 4 | 5 | import java.io.IOException; 6 | 7 | import static com.google.common.base.Preconditions.checkNotNull; 8 | 9 | final class SynchronizedBackOff implements BackOff { 10 | private final BackOff delegate; 11 | private final Object lock = new Object(); 12 | 13 | SynchronizedBackOff(BackOff delegate) { 14 | this.delegate = checkNotNull(delegate); 15 | } 16 | 17 | @Override 18 | public void reset() throws IOException { 19 | synchronized (lock) { 20 | delegate.reset(); 21 | } 22 | } 23 | 24 | @Override 25 | public long nextBackOffMillis() throws IOException { 26 | synchronized (lock) { 27 | return delegate.nextBackOffMillis(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/net/yudichev/googlephotosupload/core/EmptyOptional.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import org.hamcrest.Description; 4 | import org.hamcrest.TypeSafeDiagnosingMatcher; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * Matches an empty Optional. 10 | */ 11 | class EmptyOptional extends TypeSafeDiagnosingMatcher> { 12 | 13 | @Override 14 | protected boolean matchesSafely(Optional item, Description mismatchDescription) { 15 | if (item.isPresent()) { 16 | mismatchDescription 17 | .appendText("was present with ") 18 | .appendValue(item.get()); 19 | return false; 20 | } 21 | return true; 22 | } 23 | 24 | @Override 25 | public void describeTo(Description description) { 26 | description.appendText("an Optional that's empty"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/net/yudichev/googlephotosupload/core/MockGooglePhotosModule.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.common.inject.BaseLifecycleComponentModule; 4 | import net.yudichev.jiotty.common.inject.ExposedKeyModule; 5 | import net.yudichev.jiotty.connector.google.photos.GooglePhotosClient; 6 | 7 | import static com.google.common.base.Preconditions.checkNotNull; 8 | 9 | final class MockGooglePhotosModule extends BaseLifecycleComponentModule implements ExposedKeyModule { 10 | private final GooglePhotosClient googlePhotosClient; 11 | 12 | MockGooglePhotosModule(GooglePhotosClient googlePhotosClient) { 13 | this.googlePhotosClient = checkNotNull(googlePhotosClient); 14 | } 15 | 16 | @Override 17 | protected void configure() { 18 | bind(getExposedKey()).toInstance(googlePhotosClient); 19 | expose(getExposedKey()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/SupportPane.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/packaging-resources/macOS/createicns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | mkdir MyIcon.iconset 3 | sips -z 16 16 ../Icon1024.png --out MyIcon.iconset/icon_16x16.png 4 | sips -z 32 32 ../Icon1024.png --out MyIcon.iconset/icon_16x16@2x.png 5 | sips -z 32 32 ../Icon1024.png --out MyIcon.iconset/icon_32x32.png 6 | sips -z 64 64 ../Icon1024.png --out MyIcon.iconset/icon_32x32@2x.png 7 | sips -z 128 128 ../Icon1024.png --out MyIcon.iconset/icon_128x128.png 8 | sips -z 256 256 ../Icon1024.png --out MyIcon.iconset/icon_128x128@2x.png 9 | sips -z 256 256 ../Icon1024.png --out MyIcon.iconset/icon_256x256.png 10 | sips -z 512 512 ../Icon1024.png --out MyIcon.iconset/icon_256x256@2x.png 11 | sips -z 512 512 ../Icon1024.png --out MyIcon.iconset/icon_512x512.png 12 | cp ../Icon1024.png MyIcon.iconset/icon_512x512@2x.png 13 | iconutil -c icns MyIcon.iconset -o "out/Jiotty Photos Uploader.icns" 14 | cp "out/Jiotty Photos Uploader.icns" "out/Jiotty Photos Uploader-volume.icns" 15 | rm -R MyIcon.iconset 16 | -------------------------------------------------------------------------------- /src/main/java/net/yudichev/googlephotosupload/core/AddToAlbumStrategy.java: -------------------------------------------------------------------------------- 1 | package net.yudichev.googlephotosupload.core; 2 | 3 | import net.yudichev.jiotty.connector.google.photos.GooglePhotosAlbum; 4 | 5 | import java.nio.file.Path; 6 | import java.util.List; 7 | import java.util.Optional; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.function.BiFunction; 10 | import java.util.function.Function; 11 | 12 | interface AddToAlbumStrategy { 13 | CompletableFuture addToAlbum(CompletableFuture> createMediaDataResultsFuture, 14 | Optional googlePhotosAlbum, 15 | ProgressStatus fileProgressStatus, 16 | BiFunction, List, CompletableFuture>> createMediaItems, 17 | Function itemStateRetriever); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/PreferencePatternEditor.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |