Skip to content

Commit 421f31a

Browse files
tobiasKaminskyalperozturk96
authored andcommitted
wip
Signed-off-by: tobiasKaminsky <[email protected]>
1 parent 0b613fe commit 421f31a

File tree

3 files changed

+251
-216
lines changed

3 files changed

+251
-216
lines changed

app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,20 @@ class ComposeActivity : DrawerActivity() {
5050
setContentView(binding.root)
5151

5252
val destinationId = intent.getIntExtra(DESTINATION, -1)
53-
var title = intent.getStringExtra(TITLE_STRING)
53+
val titleId = intent.getIntExtra(TITLE, R.string.empty)
5454

55-
if (title == null || title.isEmpty()) {
56-
title = getString(intent.getIntExtra(TITLE, R.string.empty))
55+
if (destinationId == 0) {
56+
setupDrawer()
57+
58+
setupToolbarShowOnlyMenuButtonAndTitle(getString(titleId)) {
59+
openDrawer()
60+
}
61+
} else {
62+
setSupportActionBar(null)
63+
if (findViewById<View?>(R.id.appbar) != null) {
64+
findViewById<View?>(R.id.appbar)?.visibility = View.GONE
65+
}
5766
}
58-
//
59-
// if (destination == ComposeDestination.AssistantScreen) {
60-
// setupDrawer()
61-
//
62-
// setupToolbarShowOnlyMenuButtonAndTitle(title) {
63-
// openDrawer()
64-
// }
65-
// } else {
66-
// setSupportActionBar(null)
67-
// if (findViewById<View?>(R.id.appbar) != null) {
68-
// findViewById<View?>(R.id.appbar)?.visibility = View.GONE
69-
// }
70-
// }
7167

7268
binding.composeView.setContent {
7369
MaterialTheme(
@@ -81,7 +77,7 @@ class ComposeActivity : DrawerActivity() {
8177

8278
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
8379
android.R.id.home -> {
84-
super.onBackPressed()
80+
toggleDrawer()
8581
true
8682
}
8783
else -> super.onOptionsItemSelected(item)
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2025 Your Name <[email protected]>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
package com.nextcloud.ui.fileactions
9+
10+
import android.content.Context
11+
import android.content.Intent
12+
import android.graphics.Canvas
13+
import android.graphics.drawable.PictureDrawable
14+
import android.view.LayoutInflater
15+
import android.view.View
16+
import androidx.appcompat.content.res.AppCompatResources
17+
import androidx.core.graphics.createBitmap
18+
import androidx.core.graphics.drawable.toDrawable
19+
import androidx.core.net.toUri
20+
import com.google.gson.Gson
21+
import com.google.gson.GsonBuilder
22+
import com.google.gson.JsonElement
23+
import com.google.gson.JsonParser
24+
import com.google.gson.JsonSyntaxException
25+
import com.google.gson.reflect.TypeToken
26+
import com.nextcloud.android.lib.resources.clientintegration.ClientIntegrationUI
27+
import com.nextcloud.android.lib.resources.clientintegration.Element
28+
import com.nextcloud.android.lib.resources.clientintegration.ElementTypeAdapter
29+
import com.nextcloud.android.lib.resources.clientintegration.Endpoint
30+
import com.nextcloud.android.lib.resources.clientintegration.TooltipResponse
31+
import com.nextcloud.client.account.User
32+
import com.nextcloud.common.JSONRequestBody
33+
import com.nextcloud.operations.GetMethod
34+
import com.nextcloud.operations.PostMethod
35+
import com.nextcloud.ui.composeActivity.ComposeActivity
36+
import com.nextcloud.ui.composeActivity.ComposeDestination
37+
import com.nextcloud.utils.GlideHelper
38+
import com.nextcloud.utils.extensions.showToast
39+
import com.owncloud.android.R
40+
import com.owncloud.android.databinding.FileActionsBottomSheetBinding
41+
import com.owncloud.android.databinding.FileActionsBottomSheetItemBinding
42+
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
43+
import com.owncloud.android.lib.ocs.ServerResponse
44+
import com.owncloud.android.lib.resources.status.Method
45+
import com.owncloud.android.utils.DisplayUtils
46+
import com.owncloud.android.utils.theme.ViewThemeUtils
47+
import kotlinx.coroutines.CoroutineScope
48+
import kotlinx.coroutines.Dispatchers
49+
import kotlinx.coroutines.launch
50+
import kotlinx.coroutines.withContext
51+
import okhttp3.RequestBody
52+
import org.apache.commons.httpclient.HttpStatus
53+
import java.io.IOException
54+
55+
class ClientIntegration(
56+
private var sheet: FileActionsBottomSheet,
57+
private var user: User,
58+
private var context: Context
59+
) {
60+
61+
// @RequiresApi(Build.VERSION_CODES.Q)
62+
fun inflateClientIntegrationActionView(
63+
endpoint: Endpoint,
64+
layoutInflater: LayoutInflater,
65+
binding: FileActionsBottomSheetBinding,
66+
viewModel: FileActionsViewModel,
67+
viewThemeUtils: ViewThemeUtils
68+
): View {
69+
val itemBinding = FileActionsBottomSheetItemBinding.inflate(layoutInflater, binding.fileActionsList, false)
70+
.apply {
71+
root.setOnClickListener {
72+
if (viewModel.uiState.value is FileActionsViewModel.UiState.LoadedForSingleFile) {
73+
val singleFile = (viewModel.uiState.value as FileActionsViewModel.UiState.LoadedForSingleFile)
74+
75+
val fileId = singleFile.titleFile?.localId.toString()
76+
val filePath = singleFile.titleFile?.remotePath.toString()
77+
78+
requestClientIntegration(endpoint, fileId, filePath)
79+
} else {
80+
requestClientIntegration(endpoint, "", "")
81+
}
82+
}
83+
text.text = endpoint.name
84+
85+
if (endpoint.icon != null) {
86+
CoroutineScope(Dispatchers.IO).launch {
87+
val client = OwnCloudClientManagerFactory.getDefaultSingleton()
88+
.getNextcloudClientFor(user.toOwnCloudAccount(), context)
89+
90+
val drawable =
91+
GlideHelper.getDrawable(context, client, client.baseUri.toString() + endpoint.icon)
92+
?.mutate()
93+
94+
val px = DisplayUtils.convertDpToPixel(
95+
context.resources.getDimension(R.dimen.iconized_single_line_item_icon_size),
96+
context
97+
)
98+
val returnedBitmap =
99+
createBitmap(drawable?.intrinsicWidth ?: px, drawable?.intrinsicHeight ?: px)
100+
101+
val canvas = Canvas(returnedBitmap)
102+
canvas.drawPicture((drawable as PictureDrawable).picture)
103+
104+
val d = returnedBitmap.toDrawable(context.resources)
105+
106+
val tintedDrawable = viewThemeUtils.platform.tintDrawable(
107+
context,
108+
d
109+
)
110+
111+
withContext(Dispatchers.Main) {
112+
icon.setImageDrawable(tintedDrawable)
113+
}
114+
}
115+
} else {
116+
val tintedDrawable = viewThemeUtils.platform.tintDrawable(
117+
context,
118+
AppCompatResources.getDrawable(context, R.drawable.ic_activity)!!
119+
)
120+
121+
icon.setImageDrawable(tintedDrawable)
122+
}
123+
}
124+
return itemBinding.root
125+
}
126+
127+
private fun requestClientIntegration(endpoint: Endpoint, fileId: String, filePath: String) {
128+
CoroutineScope(Dispatchers.IO).launch {
129+
val client = OwnCloudClientManagerFactory.getDefaultSingleton()
130+
.getNextcloudClientFor(user.toOwnCloudAccount(), context)
131+
132+
// construct url
133+
var url = (client.baseUri.toString() + endpoint.url).toUri()
134+
.buildUpon()
135+
.appendQueryParameter("format", "json")
136+
.build()
137+
.toString()
138+
139+
// Always replace known placeholder in url
140+
url = url.replace("{filePath}", filePath, false)
141+
url = url.replace("{fileId}", fileId, false)
142+
143+
val method = when (endpoint.method) {
144+
Method.POST -> {
145+
val requestBody = if (endpoint.params?.isNotEmpty() == true) {
146+
val jsonRequestBody = JSONRequestBody()
147+
endpoint.params!!.forEach {
148+
when (it.value) {
149+
"{filePath}" -> jsonRequestBody.put(it.key, filePath)
150+
"{fileId}" -> jsonRequestBody.put(it.key, fileId)
151+
}
152+
}
153+
154+
jsonRequestBody.get()
155+
} else {
156+
RequestBody.EMPTY
157+
}
158+
159+
PostMethod(url, true, requestBody)
160+
}
161+
162+
else -> GetMethod(url, true)
163+
}
164+
165+
val result = try {
166+
client.execute(method)
167+
} catch (_: IOException) {
168+
context.showToast(context.resources.getString(R.string.failed_to_start_action))
169+
}
170+
val response = method.getResponseBodyAsString()
171+
172+
var output: ClientIntegrationUI?
173+
try {
174+
output = parseClientIntegrationResult(response)
175+
if (output.root != null) {
176+
startClientIntegration(endpoint, output)
177+
} else {
178+
val tooltipResponse = parseTooltipResult(response)
179+
180+
context.showToast(tooltipResponse.tooltip)
181+
}
182+
} catch (e: JsonSyntaxException) {
183+
if (result == HttpStatus.SC_OK) {
184+
context.showToast(context.resources.getString(R.string.action_triggered))
185+
} else {
186+
context.showToast(context.resources.getString(R.string.failed_to_start_action))
187+
}
188+
}
189+
sheet.dismiss()
190+
}
191+
}
192+
193+
private fun startClientIntegration(endpoint: Endpoint, clientIntegrationUI: ClientIntegrationUI) {
194+
CoroutineScope(Dispatchers.IO).launch {
195+
val composeActivity = Intent(context, ComposeActivity::class.java)
196+
composeActivity.putExtra(ComposeActivity.DESTINATION, ComposeDestination.ClientIntegrationScreen(null).id)
197+
composeActivity.putExtra(ComposeActivity.ARGS_CLIENT_INTEGRATION_UI, clientIntegrationUI)
198+
199+
composeActivity.putExtra(ComposeActivity.TITLE, endpoint.name)
200+
context.startActivity(composeActivity)
201+
sheet.dismiss()
202+
}
203+
}
204+
205+
private fun parseClientIntegrationResult(response: String?): ClientIntegrationUI {
206+
val gson =
207+
GsonBuilder()
208+
.registerTypeHierarchyAdapter(Element::class.java, ElementTypeAdapter())
209+
.create()
210+
211+
val element: JsonElement = JsonParser.parseString(response)
212+
return gson
213+
.fromJson(element, object : TypeToken<ServerResponse<ClientIntegrationUI>>() {})
214+
.ocs
215+
.data
216+
}
217+
218+
private fun parseTooltipResult(response: String?): TooltipResponse {
219+
val element: JsonElement = JsonParser.parseString(response)
220+
return Gson()
221+
.fromJson(element, object : TypeToken<ServerResponse<TooltipResponse>>() {})
222+
.ocs
223+
.data
224+
}
225+
}

0 commit comments

Comments
 (0)