Compare commits

..

1 Commits
v0.3.0 ... main

  1. 4
      PROJECT_STATE.md
  2. 4
      README.md
  3. 4
      app/build.gradle
  4. 2
      app/src/main/AndroidManifest.xml
  5. 74
      app/src/main/java/top/outsidethebox/otbcloud/MainActivity.kt
  6. 26
      app/src/main/res/layout/activity_main.xml

4
PROJECT_STATE.md

@ -1,4 +1,4 @@
## [v0.3.0] - Streaming upload rewrite
## [v0.3.3] - Streaming upload rewrite
### Upload behavior
- Uses HttpURLConnection chunked streaming mode
@ -39,4 +39,4 @@
- Long video upload runs can still hit OutOfMemoryError
### Next target
- v0.3.0 streaming upload rewrite
- v0.3.3 streaming upload rewrite

4
README.md

@ -1,9 +1,9 @@
# OTB Cloud Android Client
## Version
v0.3.0
v0.3.3
## v0.3.0 notes
## v0.3.3 notes
- Reworked upload path to use chunked streaming mode
- Forces per-file HTTP connection teardown
- Keeps batched upload handling

4
app/build.gradle

@ -11,8 +11,8 @@ android {
applicationId "top.outsidethebox.otbcloud"
minSdk 23
targetSdk 34
versionCode 30
versionName "0.3.0"
versionCode 33
versionName "0.3.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

2
app/src/main/AndroidManifest.xml

@ -17,7 +17,7 @@
<application
android:allowBackup="true"
android:icon="@drawable/favicon"
android:label="OTB Cloud v0.3.0"
android:label="OTB Cloud v0.3.3"
android:supportsRtl="true"
android:theme="@style/Theme.OtbCloud">

74
app/src/main/java/top/outsidethebox/otbcloud/MainActivity.kt

@ -31,6 +31,10 @@ class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val executor = Executors.newSingleThreadExecutor()
private val mediaItems = mutableListOf<MediaItem>()
private var uploadMode = UploadMode.ALL
private var lastXCount = 0
private lateinit var mediaAdapter: ArrayAdapter<String>
companion object {
@ -49,7 +53,7 @@ class MainActivity : AppCompatActivity() {
private const val REQ_READ_STORAGE = 2001
// v0.3.0 upload rewrite defaults
// v0.3.3 upload rewrite defaults
private const val VIDEO_BATCH_SIZE = 2
private const val IMAGE_BATCH_SIZE = 25
private const val PAUSE_BETWEEN_FILES_MS = 350L
@ -65,6 +69,12 @@ class MainActivity : AppCompatActivity() {
BOTH
}
enum class UploadMode {
ALL,
SELECTED,
LAST_X
}
data class MediaItem(
val path: String,
val displayName: String,
@ -118,12 +128,7 @@ class MainActivity : AppCompatActivity() {
}
binding.uploadSelectedButton.setOnClickListener {
val selected = getSelectedItems()
if (selected.isEmpty()) {
Toast.makeText(this, "No media selected", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
uploadSelectedMedia(selected)
showUploadModeDialog()
}
binding.resetActivationButton.setOnClickListener {
@ -604,7 +609,60 @@ class MainActivity : AppCompatActivity() {
}
}
private fun getSelectedItems(): List<MediaItem> {
private fun showUploadModeDialog() {
val options = arrayOf("All Media", "Selected Media", "Last X Media")
android.app.AlertDialog.Builder(this)
.setTitle("Upload Mode")
.setItems(options) { _, which ->
when (which) {
0 -> {
uploadMode = UploadMode.ALL
uploadSelectedMedia(getItemsForUpload())
}
1 -> {
uploadMode = UploadMode.SELECTED
uploadSelectedMedia(getItemsForUpload())
}
2 -> {
promptForLastX()
}
}
}
.show()
}
private fun promptForLastX() {
val input = android.widget.EditText(this)
input.inputType = android.text.InputType.TYPE_CLASS_NUMBER
android.app.AlertDialog.Builder(this)
.setTitle("Last X Media")
.setMessage("Enter number of most recent items to upload")
.setView(input)
.setPositiveButton("OK") { _, _ ->
lastXCount = input.text.toString().toIntOrNull() ?: 0
if (lastXCount > 0) {
uploadMode = UploadMode.LAST_X
uploadSelectedMedia(getItemsForUpload())
} else {
Toast.makeText(this, "Invalid number", Toast.LENGTH_SHORT).show()
}
}
.setNegativeButton("Cancel", null)
.show()
}
private fun getItemsForUpload(): List<MediaItem> {
return when (uploadMode) {
UploadMode.ALL -> mediaItems
UploadMode.SELECTED -> getSelectedItems()
UploadMode.LAST_X -> mediaItems.take(lastXCount)
}
}
private fun getSelectedItems(): List<MediaItem> {
val selected = mutableListOf<MediaItem>()
for (i in mediaItems.indices) {
if (binding.mediaListView.isItemChecked(i)) {

26
app/src/main/res/layout/activity_main.xml

@ -15,7 +15,7 @@
android:id="@+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OTB Cloud v0.3.0"
android:text="OTB Cloud v0.3.3"
android:textColor="#FFFFFF"
android:textSize="28sp"
android:textStyle="bold"
@ -25,7 +25,7 @@
android:id="@+id/subtitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android Backup Client v0.3.0"
android:text="Android Backup Client v0.3.3"
android:textColor="#B8C7E0"
android:textSize="16sp"
android:layout_marginTop="8dp"
@ -78,6 +78,7 @@
android:text="Use New Token"
android:layout_marginBottom="12dp" />
<Button
android:id="@+id/scanButton"
android:layout_width="match_parent"
@ -121,7 +122,7 @@
android:id="@+id/uploadSelectedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Upload Selected" />
android:text="Upload" />
<TextView
android:id="@+id/selectionInfoText"
@ -133,6 +134,17 @@
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp" />
<TextView
android:id="@+id/statusText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Ready"
android:textColor="#7CC7F5"
android:textSize="14sp"
android:layout_marginTop="0dp"
android:layout_marginBottom="12dp" />
<ListView
android:id="@+id/mediaListView"
android:layout_width="match_parent"
@ -143,14 +155,6 @@
android:dividerHeight="1dp" />
</LinearLayout>
<TextView
android:id="@+id/statusText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Ready"
android:textColor="#B8C7E0"
android:textSize="14sp"
android:layout_marginTop="16dp" />
</LinearLayout>
</ScrollView>

Loading…
Cancel
Save