Skip to content

Commit

Permalink
feat: Add YandexDisk integration
Browse files Browse the repository at this point in the history
Signed-off-by: Andrey Slyusar <[email protected]>
  • Loading branch information
reysand committed Feb 26, 2024
1 parent 17308d0 commit 4daaef1
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 15 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ android {
minSdk = 33
targetSdk = 34
versionCode = 3
versionName = "0.1.2"
versionName = "0.1.3"

manifestPlaceholders["YANDEX_CLIENT_ID"] = secretsProperties["YANDEX_CLIENT_ID"] as String

Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/reysand/files/data/AppContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ package com.reysand.files.data
import android.content.Context
import com.reysand.files.data.local.FileLocalDataSource
import com.reysand.files.data.remote.FileOneDriveDataSource
import com.reysand.files.data.remote.FileYandexDiskDataSource
import com.reysand.files.data.remote.YandexUserDataSource
import com.reysand.files.data.repository.FileRepository
import com.reysand.files.data.repository.OneDriveRepository
import com.reysand.files.data.repository.YandexDiskRepository
import com.reysand.files.data.repository.YandexUserRepository
import com.reysand.files.data.util.MicrosoftService
import com.reysand.files.data.util.YandexService
Expand All @@ -31,6 +33,8 @@ interface AppContainer {

val oneDriveRepository: OneDriveRepository

val yandexDiskRepository: YandexDiskRepository

val yandexUserRepository: YandexUserRepository

val microsoftService: MicrosoftService
Expand All @@ -48,6 +52,10 @@ class DefaultAppContainer(context: Context) : AppContainer {
FileOneDriveDataSource(microsoftService)
}

override val yandexDiskRepository: YandexDiskRepository by lazy {
FileYandexDiskDataSource(yandexService)
}

override val yandexUserRepository: YandexUserRepository by lazy {
YandexUserDataSource()
}
Expand Down
54 changes: 54 additions & 0 deletions app/src/main/java/com/reysand/files/data/model/YandexDisk.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2024 Andrey Slyusar
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reysand.files.data.model

import com.google.gson.annotations.SerializedName

/**
* Data class representing a Yandex.Disk object.
*
* @property embedded The embedded files.
*/
data class YandexDisk(
@SerializedName("_embedded")
val embedded: Embedded
)

/**
* Data class representing the embedded files from Yandex.Disk.
*
* @property items The list of files.
*/
data class Embedded(
val items: List<YandexDiskFile>
)

/**
* Data class representing a file from Yandex.Disk.
*
* @property name The name of the file.
* @property type The type of the file.
* @property path The path of the file.
* @property size The size of the file in bytes.
* @property modified The timestamp of the last modification in ISO8601.
*/
data class YandexDiskFile(
val name: String,
val type: String,
val path: String,
val size: Long,
val modified: String
)
31 changes: 31 additions & 0 deletions app/src/main/java/com/reysand/files/data/model/YandexDiskQuota.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2024 Andrey Slyusar
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reysand.files.data.model

import com.google.gson.annotations.SerializedName

/**
* Data class representing the quota of a Yandex.Disk account.
*
* @property total The total quota of the Yandex.Disk account.
* @property used The used quota of the Yandex.Disk account.
*/
data class YandexDiskQuota(
@SerializedName("total_space")
val total: Long,
@SerializedName("used_space")
val used: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright 2024 Andrey Slyusar
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reysand.files.data.remote

import android.util.Log
import com.reysand.files.data.model.FileModel
import com.reysand.files.data.model.YandexDiskFile
import com.reysand.files.data.repository.YandexDiskRepository
import com.reysand.files.data.util.FileDateFormatter
import com.reysand.files.data.util.FileSizeFormatter
import com.reysand.files.data.util.YandexDiskService
import com.reysand.files.data.util.YandexService
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

private const val TAG = "FileYandexDiskDataSource"

class FileYandexDiskDataSource(private val yandexService: YandexService) : YandexDiskRepository {

private val yandexAPIService: YandexDiskService by lazy {
Retrofit.Builder()
.baseUrl("https://cloud-api.yandex.net/v1/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(YandexDiskService::class.java)
}

override suspend fun getStorageFreeSpace(): String {
var freeSpace = 0L

try {
val response = yandexAPIService.getDisk(yandexService.token?.value ?: "")
Log.d(TAG, "YandexService: $response")

if (response.isSuccessful) {
freeSpace = (response.body()?.total ?: 0) - (response.body()?.used ?: 0)
}
} catch (e: Exception) {
e.printStackTrace()
}
return FileSizeFormatter.getFormattedSize(freeSpace)
}

override suspend fun getFiles(path: String): List<FileModel> {
val files = mutableListOf<FileModel>()

try {
val response = yandexAPIService.getFiles(yandexService.token?.value ?: "", path)
Log.d(TAG, "YandexService: $response")

if (response.isSuccessful) {
for (item in response.body()?.embedded?.items!!) {
files.add(createFileModel(item))
}
}
} catch (e: Exception) {
e.printStackTrace()
}

return files
}

override suspend fun moveFile(source: String, destination: String): Boolean {
val response = yandexAPIService.moveFile(
yandexService.token?.value ?: "",
source,
destination
)
Log.d(TAG, "YandexService: $response")

return response.isSuccessful
}

override suspend fun copyFile(source: String, destination: String): Boolean {
val response = yandexAPIService.copyFile(
yandexService.token?.value ?: "",
source,
destination
)
Log.d(TAG, "YandexService: $response")

return response.isSuccessful
}

override suspend fun renameFile(from: String, to: String): Boolean {
val response = yandexAPIService.moveFile(
yandexService.token?.value ?: "",
from,
if (from.contains('/')) {
from.substringBeforeLast('/') + "/" + to
} else {
to
}
)
Log.d(TAG, "YandexService: $response")

return response.isSuccessful
}

override suspend fun deleteFile(path: String): Boolean {
val response = yandexAPIService.deleteFile(yandexService.token?.value ?: "", path)
Log.d(TAG, "YandexService: $response")

return response.isSuccessful
}

/**
* Creates a [FileModel] object from a [YandexDiskFile] instance.
*
* @param file The [YandexDiskFile] instance to create a [FileModel] from.
* @return A [FileModel] object representing the given file.
*/
private fun createFileModel(file: YandexDiskFile): FileModel {
return FileModel(
name = file.name,
path = getPath(file.path),
fileType = if (file.type == "dir") FileModel.FileType.DIRECTORY else FileModel.FileType.OTHER,
size = file.size,
lastModified = FileDateFormatter.convertToUnixTimestamp(file.modified)
)
}

/**
* Generate a new path for a file.
* Removes the "disk:/" part of the path.
*
* @param path The path of the file.
*/
private fun getPath(path: String): String {
return path.substringAfterLast(":")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2024 Andrey Slyusar
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reysand.files.data.repository

import com.reysand.files.data.model.FileModel

interface YandexDiskRepository {

/**
* Retrieves the free space of the storage.
*
* @return A formatted string containing the free space of the storage.
*/
suspend fun getStorageFreeSpace(): String

/**
* Retrieves a list of [FileModel] objects from the specified path.
*
* @param path The path to the directory containing the files.
* @return A list of [FileModel] objects.
*/
suspend fun getFiles(path: String): List<FileModel>

/**
* Move a file from one path to another.
*
* @param source The original path of the file.
* @param destination The new path of the file.
* @return A boolean value indicating the success of the operation.
*/
suspend fun moveFile(source: String, destination: String): Boolean

/**
* Copy a file from one path to another.
*
* @param source The original path of the file.
* @param destination The new path of the file.
* @return A boolean value indicating the success of the operation.
*/
suspend fun copyFile(source: String, destination: String): Boolean

/**
* Rename a file.
*
* @param from The original path of the file.
* @param to The new path of the file.
* @return A boolean value indicating the success of the operation.
*/
suspend fun renameFile(from: String, to: String): Boolean

/**
* Delete a file.
*
* @param path The path of the file to delete.
* @return A boolean value indicating the success of the operation.
*/
suspend fun deleteFile(path: String): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ object FileDateFormatter {
formattedDate = date.replace(".$fractionalSeconds", ".$fractionalSeconds"
.padEnd(4, '0'))
}
} else if (date.contains("+")) {
formattedDate = date.replace("+00:00", ".000Z")
} else {
formattedDate = date.replace("Z", ".000Z")
}
Expand Down
Loading

0 comments on commit 4daaef1

Please sign in to comment.