Browse Source

Add Google Drive presets improvement. cryptomator/2921
- The code now defaults to searching through '~/Library/CloudStorage/GoogleDrive-*/*' before using the fallback options.

Siard 1 year ago
parent
commit
17057e8f8d

+ 77 - 11
src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java

@@ -3,39 +3,105 @@ package org.cryptomator.common.locationpresets;
 import org.cryptomator.integrations.common.CheckAvailability;
 import org.cryptomator.integrations.common.OperatingSystem;
 
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
 import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
-import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
 
-@OperatingSystem(WINDOWS)
 @OperatingSystem(MAC)
-@CheckAvailability
 public final class GoogleDriveLocationPresetsProvider implements LocationPresetsProvider {
+	private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath();
+	private static final Predicate<String> PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate();
 
-	private static final List<Path> LOCATIONS = Arrays.asList( //
+	private static final List<Path> FALLBACK_LOCATIONS = Arrays.asList( //
 			LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive"), //
 			LocationPresetsProvider.resolveLocation("~/Google Drive/My Drive"), //
 			LocationPresetsProvider.resolveLocation("~/GoogleDrive"), //
 			LocationPresetsProvider.resolveLocation("~/Google Drive") //
 	);
 
+	@Override
+	public Stream<LocationPreset> getLocations() {
+		if(isLocationPresent()) {
+			return getCloudStorageDirLocations();
+		} else if(FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory)) {
+			return getFallbackLocation();
+		} else {
+			return Stream.of();
+		}
+	}
+
 	@CheckAvailability
 	public static boolean isPresent() {
-		return LOCATIONS.stream().anyMatch(Files::isDirectory);
+		return isLocationPresent() || FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory);
 	}
 
-	@Override
-	public Stream<LocationPreset> getLocations() {
-		return LOCATIONS.stream() //
+	public static boolean isLocationPresent() {
+		try (DirectoryStream<Path> stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) {
+			return stream.iterator().hasNext();
+		} catch (IOException e) {
+			return false;
+		}
+	}
+
+	/**
+	 * Returns Google Drive preset String.
+	 *
+	 * @param accountPath The path to the Google Drive account directory (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username})
+	 * @param drivePath The path to the Google Drive file directory, within the account directory. (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username/drive_name})
+	 * @return {@code String}. For example: "Google Drive - username - drive_name"
+	 */
+	private String getDriveLocationString(Path accountPath, Path drivePath) {
+		String accountName = accountPath.getFileName().toString().replace("GoogleDrive-", "");
+		String driveName = drivePath.getFileName().toString();
+
+		return STR."Google Drive - \{accountName} - \{driveName}";
+	}
+
+	/**
+	 * Handles searching through {@code ~/Library/CloudStorage/} for directories with the "{@code GoogleDrive-*}" pattern,
+	 * and returns the corresponding presets.
+	 *
+	 * @return {@code Stream<LocationPreset>}. Displays as "{@code Google Drive - username - drive_name}"
+	 */
+	private Stream<LocationPreset> getCloudStorageDirLocations() {
+		try (var dirStream = Files.list(LOCATION)) {
+			var presets = dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()))
+					.flatMap(accountPath -> {
+						try {
+							return Files.list(accountPath)
+									.filter(Files::isDirectory)
+									.map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath));
+						} catch (IOException e) {
+							throw new RuntimeException(e);
+						}
+					}).toList();
+			return presets.stream();
+		}
+		catch (IOException | UncheckedIOException e) {
+			return Stream.of();
+		}
+	}
+
+	/**
+	 * Uses {@code FALLBACK_LOCATIONS} for directories as fallback, if {@code ~/Library/CloudStorage/} isn't present.
+	 * Returns the corresponding presets.
+	 *
+	 * @return {@code Stream<LocationPreset>}. Displays as "{@code Google Drive}"
+	 */
+	private Stream<LocationPreset> getFallbackLocation() {
+		return FALLBACK_LOCATIONS.stream() //
 				.filter(Files::isDirectory) //
-				.map(location -> new LocationPreset("Google Drive", location)) //
-				.findFirst() //
+				.map(location -> new LocationPreset("Google Drive", location))
+				.findFirst()
 				.stream();
 	}
-
 }