Skip to content

Commit 7c64cc6

Browse files
committed
Beta 5 almost
1 parent dcaaea1 commit 7c64cc6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3000
-352
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ dependencies {
6969
implementation("com.google.firebase:firebase-analytics-ktx:21.3.0")
7070

7171
// TPU
72+
implementation("com.github.wax911:android-emojify:1.7.1")
73+
implementation("androidx.activity:activity:1.7.2")
7274
implementation("com.google.accompanist:accompanist-permissions:0.31.4-beta")
7375
implementation("io.mhssn:colorpicker:1.0.0")
7476
implementation("com.google.accompanist:accompanist-insets:0.22.0-rc")

app/release/app-release.apk

354 KB
Binary file not shown.

app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
android:theme="@style/Theme.PrivateUploader"
2020
android:usesCleartextTraffic="true"
2121
android:windowSoftInputMode="adjustResize"
22+
android:enableOnBackInvokedCallback="true"
23+
android:name="com.troplo.privateuploader.TpuApp"
2224
tools:targetApi="31">
2325
<meta-data
2426
android:name="com.google.firebase.messaging.default_notification_channel_id"
@@ -71,5 +73,9 @@
7173
<category android:name="android.intent.category.LAUNCHER" />
7274
</intent-filter>
7375
</activity>
76+
<activity
77+
android:name=".UploadResponseActivity"
78+
android:exported="true"
79+
></activity>
7480
</application>
7581
</manifest>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.troplo.privateuploader
2+
3+
import android.app.Application
4+
import androidx.startup.AppInitializer
5+
import io.wax911.emojify.EmojiManager
6+
import io.wax911.emojify.initializer.EmojiInitializer
7+
8+
class TpuApp : Application() {
9+
10+
/**
11+
* Application scope bound emojiManager, you could keep a reference to this object in a
12+
* dependency injector framework like as a singleton in `Hilt`, `Dagger` or `Koin`
13+
*/
14+
internal val emojiManager: EmojiManager by lazy {
15+
// should already be initialized if we haven't disabled initialization in manifest
16+
// see: https://developer.android.com/topic/libraries/app-startup#disable-individual
17+
AppInitializer.getInstance(this)
18+
.initializeComponent(EmojiInitializer::class.java)
19+
}
20+
}

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

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,39 @@ package com.troplo.privateuploader
33
import android.Manifest
44
import android.content.Intent
55
import android.content.pm.PackageManager
6+
import android.net.Uri
67
import android.os.Build
78
import android.os.Bundle
9+
import android.provider.OpenableColumns
810
import android.util.Log
911
import androidx.activity.ComponentActivity
1012
import androidx.activity.compose.setContent
1113
import androidx.activity.result.contract.ActivityResultContracts
1214
import androidx.core.content.ContextCompat
15+
import androidx.startup.AppInitializer
1316
import com.google.android.gms.common.GoogleApiAvailability
17+
import com.troplo.privateuploader.api.RequestBodyWithProgress
1418
import com.troplo.privateuploader.api.SessionManager
1519
import com.troplo.privateuploader.api.SocketHandler
1620
import com.troplo.privateuploader.api.SocketHandlerService
1721
import com.troplo.privateuploader.api.TpuApi
22+
import com.troplo.privateuploader.api.TpuFunctions
23+
import com.troplo.privateuploader.api.stores.CollectionStore
24+
import com.troplo.privateuploader.api.stores.UploadStore
1825
import com.troplo.privateuploader.api.stores.UserStore
26+
import com.troplo.privateuploader.data.model.UploadTarget
1927
import com.troplo.privateuploader.ui.theme.PrivateUploaderTheme
28+
import io.wax911.emojify.EmojiManager
29+
import io.wax911.emojify.initializer.EmojiInitializer
30+
import kotlinx.coroutines.CoroutineScope
31+
import kotlinx.coroutines.Dispatchers
32+
import kotlinx.coroutines.launch
33+
import kotlinx.coroutines.withContext
34+
import okhttp3.MediaType.Companion.toMediaType
35+
import okhttp3.MediaType.Companion.toMediaTypeOrNull
36+
import okhttp3.MultipartBody
37+
import okhttp3.RequestBody.Companion.asRequestBody
38+
2039

2140
class MainActivity : ComponentActivity() {
2241
override fun onResume() {
@@ -129,5 +148,110 @@ class MainActivity : ComponentActivity() {
129148
}
130149
}
131150
}
151+
152+
fun upload(files: List<UploadTarget>) {
153+
UploadStore.uploads = files.toMutableList()
154+
155+
val filesBody = files.map { file ->
156+
TpuFunctions.uriToFile(file.uri, this, file.name)
157+
}
158+
159+
CoroutineScope(Dispatchers.IO).launch {
160+
var totalSize = 0L
161+
162+
// Calculate total file size
163+
filesBody.forEach { file ->
164+
totalSize += file.length()
165+
}
166+
167+
val parts = mutableListOf<MultipartBody.Part>()
168+
169+
val requestFile = RequestBodyWithProgress(
170+
filesBody,
171+
RequestBodyWithProgress.ContentType.ANY,
172+
progressCallback = { progress ->
173+
Log.d("TPU.Upload", "Progress: $progress")
174+
UploadStore.globalProgress.value = progress
175+
}
176+
)
177+
178+
filesBody.forEach { file ->
179+
val part = MultipartBody.Part.createFormData(
180+
"attachments",
181+
file.name,
182+
requestFile
183+
)
184+
parts.add(part)
185+
}
186+
187+
val response = TpuApi.retrofitService.uploadFiles(parts).execute()
188+
response.body()?.let {
189+
UploadStore.globalProgress.value = 0f
190+
UploadStore.uploads = mutableListOf()
191+
}
192+
}
193+
}
194+
195+
@Deprecated("Deprecated in Java")
196+
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
197+
super.onActivityResult(requestCode, resultCode, data)
198+
if (requestCode == UploadStore.intentCode && resultCode == RESULT_OK) {
199+
if (data != null) {
200+
if (data.clipData != null) {
201+
// Multiple files were selected
202+
val clipData = data.clipData
203+
if (clipData != null) {
204+
val files = mutableListOf<UploadTarget>()
205+
for (i in 0 until clipData.itemCount) {
206+
Log.d("TPU.Upload", "File: ${clipData.getItemAt(i).uri}")
207+
val uri = clipData.getItemAt(i).uri
208+
files.add(UploadTarget(
209+
uri = uri,
210+
name = getFileName(uri) ?: "unknown.file"
211+
))
212+
}
213+
upload(files)
214+
}
215+
} else if (data.data != null) {
216+
val uri = data.data
217+
if (uri != null) {
218+
upload(listOf(UploadTarget(
219+
uri = uri,
220+
name = getFileName(uri) ?: "unknown.file"
221+
)))
222+
}
223+
}
224+
}
225+
}
226+
}
227+
228+
private fun getFileName(uri: Uri): String {
229+
var result: String? = null
230+
if (uri.scheme == "content") {
231+
val cursor = contentResolver.query(uri, null, null, null, null)
232+
cursor.use { c ->
233+
if (c != null && c.moveToFirst()) {
234+
val index = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
235+
result = c.getString(index)
236+
}
237+
}
238+
}
239+
if (result == null) {
240+
result = uri.path
241+
val cut = result!!.lastIndexOf('/')
242+
if (cut != -1) {
243+
result = result!!.substring(cut + 1)
244+
}
245+
}
246+
return result as String
247+
}
248+
249+
250+
internal val emojiManager: EmojiManager by lazy {
251+
// should already be initialized if we haven't disabled initialization in manifest
252+
// see: https://developer.android.com/topic/libraries/app-startup#disable-individual
253+
AppInitializer.getInstance(this)
254+
.initializeComponent(EmojiInitializer::class.java)
255+
}
132256
}
133257

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

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
package com.troplo.privateuploader
22

3+
import android.util.Log
4+
import androidx.activity.OnBackPressedCallback
5+
import androidx.activity.OnBackPressedDispatcher
6+
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
37
import androidx.compose.foundation.layout.Column
48
import androidx.compose.foundation.layout.Spacer
59
import androidx.compose.foundation.layout.fillMaxSize
10+
import androidx.compose.foundation.layout.fillMaxWidth
611
import androidx.compose.foundation.layout.height
712
import androidx.compose.foundation.layout.padding
813
import androidx.compose.foundation.rememberScrollState
914
import androidx.compose.foundation.verticalScroll
1015
import androidx.compose.material.ExperimentalMaterialApi
16+
import androidx.compose.material.LinearProgressIndicator
1117
import androidx.compose.material3.ExperimentalMaterial3Api
1218
import androidx.compose.material3.ModalDrawerSheet
1319
import androidx.compose.material3.Scaffold
1420
import androidx.compose.runtime.Composable
21+
import androidx.compose.runtime.DisposableEffect
1522
import androidx.compose.runtime.LaunchedEffect
1623
import androidx.compose.runtime.collectAsState
1724
import androidx.compose.runtime.getValue
1825
import androidx.compose.runtime.mutableStateOf
1926
import androidx.compose.runtime.remember
27+
import androidx.compose.runtime.rememberUpdatedState
2028
import androidx.compose.runtime.setValue
2129
import androidx.compose.ui.ExperimentalComposeUiApi
2230
import androidx.compose.ui.Modifier
@@ -25,6 +33,7 @@ import androidx.compose.ui.unit.dp
2533
import androidx.navigation.compose.rememberNavController
2634
import com.troplo.privateuploader.api.ChatStore
2735
import com.troplo.privateuploader.api.SocketHandler
36+
import com.troplo.privateuploader.api.stores.UploadStore
2837
import com.troplo.privateuploader.api.stores.UserStore
2938
import com.troplo.privateuploader.components.chat.MemberSidebar
3039
import com.troplo.privateuploader.components.core.BottomBarNav
@@ -34,6 +43,8 @@ import com.troplo.privateuploader.components.core.NavRoute
3443
import com.troplo.privateuploader.components.core.OverlappingPanels
3544
import com.troplo.privateuploader.components.core.PanelSurface
3645
import com.troplo.privateuploader.components.core.TopBarNav
46+
import com.troplo.privateuploader.components.core.debug.recomposeHighlighter
47+
import com.troplo.privateuploader.components.core.dialogs.EmailVerificationDialog
3748
import com.troplo.privateuploader.components.core.rememberOverlappingPanelsState
3849
import com.troplo.privateuploader.screens.HomeScreen
3950
import io.sentry.compose.SentryTraced
@@ -77,6 +88,20 @@ fun MainScreen() {
7788
openPanel = false
7889
}
7990

91+
if(panelState.isPanelsClosed) {
92+
BackPressHandler {
93+
if(navController.currentDestination?.route?.startsWith("chat/") == true) {
94+
openPanel = true
95+
} else {
96+
navController.navigateUp()
97+
}
98+
}
99+
}
100+
101+
if(user.value?.emailVerified == false) {
102+
EmailVerificationDialog()
103+
}
104+
80105
Scaffold(
81106
topBar = {
82107
if (!SocketHandler.connected.value && user.value != null) {
@@ -87,14 +112,20 @@ fun MainScreen() {
87112
openPanelFunc
88113
)
89114
}
115+
116+
if(UploadStore.globalProgress.value != 0f && UploadStore.globalProgress.value != 100f) {
117+
LinearProgressIndicator(progress = UploadStore.globalProgress.value, modifier = Modifier.fillMaxWidth(
118+
119+
))
120+
}
90121
},
91122
bottomBar = {
92123
BottomBarNav(
93124
navController = navController,
94125
panelState = panelState,
95126
closePanels = closePanelsFunc
96127
)
97-
},
128+
}
98129
) { paddingValues ->
99130
OverlappingPanels(
100131
modifier = Modifier.fillMaxSize(),
@@ -160,4 +191,29 @@ fun MainScreen() {
160191
)
161192
}
162193
}
194+
}
195+
196+
@Composable
197+
fun BackPressHandler(
198+
backPressedDispatcher: OnBackPressedDispatcher? =
199+
LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher,
200+
onBackPressed: () -> Unit
201+
) {
202+
val currentOnBackPressed by rememberUpdatedState(newValue = onBackPressed)
203+
204+
val backCallback = remember {
205+
object : OnBackPressedCallback(true) {
206+
override fun handleOnBackPressed() {
207+
currentOnBackPressed()
208+
}
209+
}
210+
}
211+
212+
DisposableEffect(key1 = backPressedDispatcher) {
213+
backPressedDispatcher?.addCallback(backCallback)
214+
215+
onDispose {
216+
backCallback.remove()
217+
}
218+
}
163219
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.troplo.privateuploader
2+
3+
import android.R
4+
import android.app.Activity
5+
import android.content.Intent
6+
import android.os.Bundle
7+
import android.util.Log
8+
import android.view.View
9+
import android.widget.Button
10+
import com.troplo.privateuploader.api.stores.UploadStore
11+
12+
13+
class UploadResponseActivity: Activity() {
14+
override fun onCreate(savedInstanceState: Bundle?) {
15+
super.onCreate(savedInstanceState)
16+
}
17+
18+
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
19+
super.onActivityResult(requestCode, resultCode, data)
20+
if (requestCode == UploadStore.intentCode && resultCode == RESULT_OK) {
21+
if (data != null) {
22+
if (data.clipData != null) {
23+
// Multiple files were selected
24+
val clipData = data.clipData
25+
if (clipData != null) {
26+
for (i in 0 until clipData.itemCount) {
27+
val uri = clipData.getItemAt(i).uri
28+
Log.d("TPU.UploadResponse", uri.toString())
29+
}
30+
}
31+
} else if (data.data != null) {
32+
// Single file was selected
33+
val uri = data.data
34+
Log.d("TPU.UploadResponse", uri.toString())
35+
}
36+
}
37+
}
38+
}
39+
}
40+

0 commit comments

Comments
 (0)