Files
AndPictures/app/src/main/java/com/bm/andpictures/NasFileSource.kt
AndPictures 6bc1f9a355 AndPictures 1.0: NAS photo sync + built-in file browser
Native Kotlin Android app (single Activity + WorkManager worker) that copies
photos newer than a stored cursor to //192.168.123.2/photo/Home as
decade/year/month, deduping by filename and NAS file size.

- SMB2/3 via smbj; transparently reconnects when the server drops an idle
  session (previously surfaced as "DiskShare has already been closed")
- MediaStore cursor store, incremental uploads, size-aware dedupe
- "Phone files" / "NAS files" browser: grid, thumbnails, full-screen preview
- Release signing read from keystore.properties (never committed)
2026-10-14 10:47:43 -07:00

64 lines
2.0 KiB
Kotlin

package com.bm.andpictures
import java.io.InputStream
/**
* Browses an SMB share starting at [rootKey]. Keys are share-relative paths
* using backslashes (matching [SmbUploader]); an empty key means the share
* root.
*/
class NasFileSource(
private val uploader: SmbUploader,
private val hostAndShare: String,
override val rootKey: String,
) : FileSource {
override val title: String get() = "NAS"
override fun list(dirKey: String): List<TileEntry> {
val entries = uploader.listEntries(dirKey)
val dirs = entries.asSequence()
.filter { it.isDirectory }
.sortedBy { it.name.lowercase() }
.map { TileEntry(it.name, joinKey(dirKey, it.name), isDirectory = true, sizeBytes = 0L, isImage = false) }
.toList()
val files = entries.asSequence()
.filter { !it.isDirectory }
.sortedBy { it.name.lowercase() }
.map {
TileEntry(
it.name,
joinKey(dirKey, it.name),
isDirectory = false,
sizeBytes = it.sizeBytes,
isImage = isImageName(it.name),
)
}
.toList()
return dirs + files
}
override fun parentOf(dirKey: String): String? {
val norm = dirKey.trim('\\', '/')
if (norm.isEmpty() || norm == rootKey.trim('\\', '/')) return null
val parent = norm.substringBeforeLast('\\', "")
return parent
}
override fun displayName(dirKey: String): String {
val norm = dirKey.trim('\\', '/').replace('\\', '/')
return if (norm.isEmpty()) "//$hostAndShare" else "//$hostAndShare/$norm"
}
override fun openStream(key: String): InputStream = uploader.openRead(key)
override fun close() {
uploader.close()
}
private fun joinKey(dir: String, name: String): String {
val d = dir.trim('\\', '/')
return if (d.isEmpty()) name else "$d\\$name"
}
}