Skip to content

Commit 3a1b318

Browse files
committed
1.0.8
1 parent 8cdbc40 commit 3a1b318

26 files changed

+231
-137
lines changed

.idea/gradle.xml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/benchmark/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

app/benchmark/build.gradle.kts

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
2+
plugins {
3+
alias(libs.plugins.androidTest)
4+
alias(libs.plugins.kotlinAndroid)
5+
}
6+
7+
android {
8+
namespace = "com.troplo.benchmark"
9+
compileSdk = 33
10+
11+
compileOptions {
12+
sourceCompatibility = JavaVersion.VERSION_1_8
13+
targetCompatibility = JavaVersion.VERSION_1_8
14+
}
15+
16+
kotlinOptions {
17+
jvmTarget = "1.8"
18+
}
19+
20+
defaultConfig {
21+
minSdk = 26
22+
targetSdk = 33
23+
24+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
25+
}
26+
27+
buildTypes {
28+
// This benchmark buildType is used for benchmarking, and should function like your
29+
// release build (for example, with minification on). It"s signed with a debug key
30+
// for easy local/CI testing.
31+
create("benchmark") {
32+
isDebuggable = true
33+
signingConfig = getByName("debug").signingConfig
34+
matchingFallbacks += listOf("release")
35+
}
36+
}
37+
38+
targetProjectPath = ":app"
39+
experimentalProperties["android.experimental.self-instrumenting"] = true
40+
}
41+
42+
dependencies {
43+
implementation(libs.androidx.test.ext.junit)
44+
implementation(libs.espresso.core)
45+
implementation(libs.uiautomator)
46+
implementation(libs.benchmark.macro.junit4)
47+
}
48+
49+
androidComponents {
50+
beforeVariants(selector().all()) {
51+
it.enable = it.buildType == "benchmark"
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<manifest />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.troplo.benchmark
2+
3+
import androidx.benchmark.macro.CompilationMode
4+
import androidx.benchmark.macro.StartupMode
5+
import androidx.benchmark.macro.StartupTimingMetric
6+
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
7+
import androidx.test.ext.junit.runners.AndroidJUnit4
8+
import org.junit.Rule
9+
import org.junit.Test
10+
import org.junit.runner.RunWith
11+
12+
/**
13+
* This is an example startup benchmark.
14+
*
15+
* It navigates to the device's home screen, and launches the default activity.
16+
*
17+
* Before running this benchmark:
18+
* 1) switch your app's active build variant in the Studio (affects Studio runs only)
19+
* 2) add `<profileable android:shell="true" />` to your app's manifest, within the `<application>` tag
20+
*
21+
* Run this benchmark from Studio to see startup measurements, and captured system traces
22+
* for investigating your app's performance.
23+
*/
24+
@RunWith(AndroidJUnit4::class)
25+
class ExampleStartupBenchmark {
26+
@get:Rule
27+
val benchmarkRule = MacrobenchmarkRule()
28+
29+
@Test
30+
fun startup() = benchmarkRule.measureRepeated(
31+
packageName = "com.troplo.privateuploader",
32+
metrics = listOf(StartupTimingMetric()),
33+
iterations = 5,
34+
startupMode = StartupMode.COLD
35+
) {
36+
pressHome()
37+
startActivityAndWait()
38+
}
39+
}

app/build.gradle.kts

+8-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ android {
1414
applicationId = "com.troplo.privateuploader"
1515
minSdk = 28
1616
targetSdk = 34
17-
versionCode = 7
18-
versionName = "1.0.7"
17+
versionCode = 8
18+
versionName = "1.0.8"
1919
multiDexEnabled = true
2020
buildConfigField("String", "SERVER_URL", "\"https://privateuploader.com\"")
2121
buildConfigField("String", "BUILD_TIME", "\"${System.currentTimeMillis()}\"")
@@ -40,6 +40,12 @@ android {
4040
debug {
4141
buildConfigField("String", "SERVER_URL", "\"http://192.168.0.12:34582\"")
4242
}
43+
create("benchmark") {
44+
initWith(buildTypes.getByName("release"))
45+
signingConfig = signingConfigs.getByName("debug")
46+
matchingFallbacks += listOf("release")
47+
isDebuggable = false
48+
}
4349
}
4450
compileOptions {
4551
sourceCompatibility = JavaVersion.VERSION_1_8

app/src/main/java/com/troplo/privateuploader/MainActivity.kt

+20-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.troplo.privateuploader
22

33
import android.Manifest
4+
import android.content.Context
45
import android.content.Intent
56
import android.content.pm.PackageManager
67
import android.net.Uri
@@ -11,6 +12,8 @@ import android.util.Log
1112
import androidx.activity.ComponentActivity
1213
import androidx.activity.compose.setContent
1314
import androidx.activity.result.contract.ActivityResultContracts
15+
import androidx.compose.runtime.mutableStateListOf
16+
import androidx.compose.runtime.toMutableStateList
1417
import androidx.core.content.ContextCompat
1518
import androidx.startup.AppInitializer
1619
import com.google.android.gms.common.GoogleApiAvailability
@@ -149,11 +152,14 @@ class MainActivity : ComponentActivity() {
149152
}
150153
}
151154

152-
fun upload(files: List<UploadTarget>) {
153-
UploadStore.uploads = files.toMutableList()
155+
fun upload(files: List<UploadTarget>, deleteOnceFinished: Boolean = true, context: Context = this) {
156+
Log.d("TPU.Upload", "Uploading ${files.size} files")
157+
if(deleteOnceFinished) {
158+
UploadStore.uploads = files.toMutableStateList()
159+
}
154160

155161
val filesBody = files.map { file ->
156-
TpuFunctions.uriToFile(file.uri, this, file.name)
162+
TpuFunctions.uriToFile(file.uri, context, file.name)
157163
}
158164

159165
CoroutineScope(Dispatchers.IO).launch {
@@ -185,9 +191,18 @@ class MainActivity : ComponentActivity() {
185191
}
186192

187193
val response = TpuApi.retrofitService.uploadFiles(parts).execute()
188-
response.body()?.let {
194+
response.body()?.let { upload ->
189195
UploadStore.globalProgress.value = 0f
190-
UploadStore.uploads = mutableListOf()
196+
if(deleteOnceFinished) {
197+
UploadStore.uploads = mutableStateListOf()
198+
} else {
199+
// set the upload status to finished
200+
UploadStore.uploads.find { it.uri == files.first().uri }?.let {
201+
it.progress = 100f
202+
it.url = upload[0].upload.attachment
203+
}
204+
Log.d("TPU.Upload", "Upload finished: ${upload[0].upload.attachment}, ${UploadStore.uploads.toList().toString()}")
205+
}
191206
}
192207
}
193208
}

app/src/main/java/com/troplo/privateuploader/api/SocketHandler.kt

+4-6
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,17 @@ object SocketHandler {
7272

7373
val message = messageEvent.message
7474
Log.d("TPU.Untagged", "Message received (SocketHandler): $message")
75+
val chat =
76+
ChatStore.chats.value.find { it.association?.id == messageEvent.association.id }
7577
if (messageEvent.association.id != ChatStore.associationId.value) {
7678
// increase unread count
77-
val chat =
78-
ChatStore.chats.value.find { it.association?.id == messageEvent.association.id }
7979
Log.d("TPU.Untagged", chat.toString())
8080
if (chat != null) {
8181
chat.unread = chat.unread?.plus(1)
82-
ChatStore.setChats(listOf(chat) + ChatStore.chats.value.filter { it.association?.id != messageEvent.association.id })
8382
}
83+
} else if(chat != null) {
84+
ChatStore.setChats(listOf(chat) + ChatStore.chats.value.filter { it.association?.id != messageEvent.association.id })
8485
}
85-
86-
// if running in background, send notification
87-
8886
}
8987
socket?.on("typing") { it ->
9088
CoroutineScope(Dispatchers.IO).launch {

app/src/main/java/com/troplo/privateuploader/api/stores/ChatStore.kt

-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ object ChatStore {
2929
var hasInit = false
3030
val searchPanel = MutableStateFlow(false)
3131

32-
// To upload to TPU, uses URI Android system
33-
var attachmentsToUpload = mutableStateListOf<UploadTarget>()
34-
3532
val chats: StateFlow<List<Chat>>
3633
get() = _chats
3734

app/src/main/java/com/troplo/privateuploader/api/stores/UploadStore.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity
66
import androidx.compose.runtime.MutableState
77
import androidx.compose.runtime.mutableFloatStateOf
88
import androidx.compose.runtime.mutableIntStateOf
9+
import androidx.compose.runtime.mutableStateListOf
910
import androidx.core.app.ActivityCompat.startActivityForResult
1011
import com.troplo.privateuploader.MainActivity
1112
import com.troplo.privateuploader.UploadResponseActivity
@@ -16,7 +17,7 @@ import java.util.Date
1617
object UploadStore {
1718
var intentCode = 0
1819
var filePath: String = ""
19-
var uploads = mutableListOf<UploadTarget>()
20+
var uploads = mutableStateListOf<UploadTarget>()
2021
var globalProgress: MutableState<Float> = mutableFloatStateOf(0f)
2122

2223
fun requestUploadIntent(activity: Activity) {

app/src/main/java/com/troplo/privateuploader/components/chat/Attachment.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.compose.ui.unit.dp
2828
import androidx.core.net.toUri
2929
import androidx.lifecycle.ViewModel
3030
import com.troplo.privateuploader.api.ChatStore
31+
import com.troplo.privateuploader.api.stores.UploadStore
3132
import com.troplo.privateuploader.api.stores.UserStore
3233
import com.troplo.privateuploader.components.chat.attachment.MyDevice
3334
import com.troplo.privateuploader.data.model.Upload
@@ -80,7 +81,7 @@ fun Attachment(openBottomSheet: MutableState<Boolean>) {
8081

8182
fun onClick(upload: Upload, tenor: Boolean = false) {
8283
openBottomSheet.value = false
83-
ChatStore.attachmentsToUpload.add(
84+
UploadStore.uploads.add(
8485
UploadTarget(
8586
uri = if (tenor) {
8687
upload.attachment.toUri()

app/src/main/java/com/troplo/privateuploader/components/chat/ChatItem.kt

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.troplo.privateuploader.components.chat
22

3-
import androidx.compose.foundation.gestures.detectTapGestures
43
import androidx.compose.foundation.layout.fillMaxWidth
54
import androidx.compose.foundation.layout.padding
65
import androidx.compose.material3.Badge
@@ -9,24 +8,24 @@ import androidx.compose.material3.MaterialTheme
98
import androidx.compose.material3.NavigationDrawerItem
109
import androidx.compose.material3.Text
1110
import androidx.compose.runtime.Composable
12-
import androidx.compose.runtime.MutableState
1311
import androidx.compose.runtime.collectAsState
1412
import androidx.compose.runtime.mutableStateOf
1513
import androidx.compose.runtime.remember
1614
import androidx.compose.ui.Modifier
17-
import androidx.compose.ui.input.pointer.pointerInput
1815
import androidx.compose.ui.unit.dp
16+
import androidx.navigation.NavController
1917
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
2018
import com.troplo.privateuploader.api.ChatStore
2119
import com.troplo.privateuploader.api.TpuFunctions
20+
import com.troplo.privateuploader.components.core.NavRoute
2221
import com.troplo.privateuploader.components.core.UserAvatar
2322
import com.troplo.privateuploader.data.model.Chat
2423

2524
@OptIn(ExperimentalMaterial3Api::class, ExperimentalGlideComposeApi::class)
2625
@Composable
2726
fun ChatItem(
2827
chat: Chat,
29-
openChat: (Int) -> Unit
28+
navController: NavController,
3029
) {
3130
val chatName = TpuFunctions.getChatName(chat)
3231
// track ChatStore.associationId, is mutableStateOf<Int>(0)
@@ -55,7 +54,9 @@ fun ChatItem(
5554
.fillMaxWidth(),
5655
onClick = {
5756
chat.association?.let {
58-
openChat(it.id)
57+
if (navController.currentDestination?.route?.startsWith("chat/") == false || id.value != it.id) {
58+
navController.navigate("${NavRoute.Chat.path}/${it.id}")
59+
}
5960
}
6061
},
6162
label = {
@@ -78,7 +79,7 @@ fun ChatItem(
7879
)
7980
}*/
8081
},
81-
selected = id.value == chat.association?.id,
82+
selected = navController.currentDestination?.route?.startsWith("chat/") == true && id.value == chat.association?.id,
8283
icon = {
8384
UserAvatar(
8485
avatar = chat.icon ?: chat.recipient?.avatar,

app/src/main/java/com/troplo/privateuploader/components/chat/MarkdownText.kt

+7-8
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,13 @@ import androidx.compose.ui.text.style.TextDecoration
2727
import androidx.compose.ui.unit.TextUnit
2828
import androidx.compose.ui.viewinterop.AndroidView
2929
import androidx.core.content.res.ResourcesCompat
30-
import com.troplo.privateuploader.TpuApp
3130
import io.noties.markwon.AbstractMarkwonPlugin
3231
import io.noties.markwon.Markwon
3332
import io.noties.markwon.MarkwonConfiguration
3433
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin
3534
import io.noties.markwon.ext.tables.TablePlugin
3635
import io.noties.markwon.html.HtmlPlugin
3736
import io.noties.markwon.linkify.LinkifyPlugin
38-
import io.wax911.emojify.parser.parseToHtmlDecimal
39-
import io.wax911.emojify.parser.parseToUnicode
4037

4138

4239
@Composable
@@ -53,7 +50,7 @@ fun MarkdownText(
5350
onClick: (() -> Unit)? = null,
5451
// this option will disable all clicks on links, inside the markdown text
5552
// it also enable the parent view to receive the click event
56-
onLinkClicked: ((String) -> Unit)? = null,
53+
onLinkClicked: (() -> Unit)? = null,
5754
onTextLayout: ((numLines: Int) -> Unit)? = null,
5855
onLongClick: (() -> Unit)? = null,
5956
) {
@@ -75,8 +72,7 @@ fun MarkdownText(
7572
maxLines = maxLines,
7673
style = style,
7774
textAlign = textAlign,
78-
viewId = viewId,
79-
onClick = onClick
75+
viewId = viewId
8076
)
8177
},
8278
update = { textView ->
@@ -88,8 +84,11 @@ fun MarkdownText(
8884
}
8985
textView.maxLines = maxLines
9086
textView.setOnLongClickListener {
87+
Log.d("MarkdownText", "onLongClick")
9188
preventLinkClick.value = true
92-
onLongClick?.invoke()
89+
if (onLongClick != null) {
90+
onLongClick()
91+
}
9392
true
9493
}
9594
}
@@ -147,7 +146,7 @@ private fun createTextView(
147146

148147
private fun createMarkdownRender(
149148
context: Context,
150-
onLinkClicked: ((String) -> Unit)? = null,
149+
onLinkClicked: (() -> Unit)? = null,
151150
preventLinkClick: MutableState<Boolean>,
152151
): Markwon {
153152
return Markwon.builder(context)

0 commit comments

Comments
 (0)