From 18b9e9a825dafdb957d35bc64512d79d9a4ec6cc Mon Sep 17 00:00:00 2001
From: wafa lakhal <4533152+wafalakhal@users.noreply.github.com>
Date: Tue, 25 Mar 2025 19:49:23 +0100
Subject: [PATCH 001/153] peer to peer navigation (#372)
* add nearby share option
* add send and receive file view
* wip on add nearbysharing navigation and start fragment
* fix pr comments
* fix pr comments
* fix PR comments
---
mobile/src/main/AndroidManifest.xml | 5 +-
.../tella/mobile/domain/entity/ServerType.kt | 2 +-
.../peertopeer/StartNearBySharingFragment.kt | 49 ++++++++++
.../peertopeer/activity/PeerToPeerActivity.kt | 17 ++++
.../adapters/connections/ServerViewHolder.kt | 14 +++
.../fragment/vault/home/HomeVaultFragment.kt | 5 +
mobile/src/main/res/drawable/ic_share.xml | 10 ++
mobile/src/main/res/drawable/ic_share_big.xml | 10 ++
.../main/res/layout/activity_peer_to_peer.xml | 43 +++++++++
.../res/layout/item_home_vault_server.xml | 56 +++++++-----
.../layout/start_near_by_sharing_fragment.xml | 91 +++++++++++++++++++
mobile/src/main/res/navigation/home.xml | 11 +++
.../res/navigation/peer_to_peer_graph.xml | 13 +++
mobile/src/main/res/values/strings.xml | 11 +++
14 files changed, 312 insertions(+), 25 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
create mode 100644 mobile/src/main/res/drawable/ic_share.xml
create mode 100644 mobile/src/main/res/drawable/ic_share_big.xml
create mode 100644 mobile/src/main/res/layout/activity_peer_to_peer.xml
create mode 100644 mobile/src/main/res/layout/start_near_by_sharing_fragment.xml
create mode 100644 mobile/src/main/res/navigation/peer_to_peer_graph.xml
diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml
index cc549d1b0..6cc4674bf 100644
--- a/mobile/src/main/AndroidManifest.xml
+++ b/mobile/src/main/AndroidManifest.xml
@@ -662,7 +662,10 @@
android:name=".views.dialog.nextcloud.NextCloudLoginFlowActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar" />
-
+
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/ServerType.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/ServerType.kt
index 31466c64b..5946e5bea 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/ServerType.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/ServerType.kt
@@ -1,5 +1,5 @@
package org.horizontal.tella.mobile.domain.entity
enum class ServerType {
- UNKNOWN, ODK_COLLECT, TELLA_UPLOAD, TELLA_RESORCES, UWAZI, GOOGLE_DRIVE, DROP_BOX, NEXTCLOUD,
+ UNKNOWN, ODK_COLLECT, TELLA_UPLOAD, TELLA_RESORCES, UWAZI, GOOGLE_DRIVE, DROP_BOX, NEXTCLOUD,PEERTOPEER
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt
new file mode 100644
index 000000000..3ebe4c6e7
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt
@@ -0,0 +1,49 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.view.isVisible
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.databinding.StartNearBySharingFragmentBinding
+import org.horizontal.tella.mobile.util.Util
+import org.horizontal.tella.mobile.util.hide
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+
+class StartNearBySharingFragment : BaseBindingFragment(
+ StartNearBySharingFragmentBinding::inflate
+) {
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initViews()
+ }
+
+ private fun initViews() {
+ binding?.apply {
+ nextBtn.hide()
+
+ learnMoreTextView.setOnClickListener {
+ baseActivity.maybeChangeTemporaryTimeout()
+ Util.startBrowserIntent(context, getString(R.string.peerToPeer_documentation_url))
+ }
+
+ sendFilesBtn.setOnClickListener { selectOption(true) }
+ receiveFilesBtn.setOnClickListener { selectOption(false) }
+ nextBtn.setOnClickListener { onNextClicked() }
+ }
+ }
+ private fun selectOption(isSend: Boolean) {
+ binding?.apply {
+ sendFilesBtn.isChecked = isSend
+ receiveFilesBtn.isChecked = !isSend
+ nextBtn.isVisible = true
+ }
+ }
+
+ private fun onNextClicked() {
+ // TODO: Implement navigation on "Next"
+ }
+
+}
+
+
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
new file mode 100644
index 000000000..81f8f350c
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
@@ -0,0 +1,17 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.activity
+
+import android.os.Bundle
+import org.horizontal.tella.mobile.databinding.ActivityPeerToPeerBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseLockActivity
+
+class PeerToPeerActivity : BaseLockActivity() {
+ private lateinit var binding: ActivityPeerToPeerBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityPeerToPeerBinding.inflate(layoutInflater)
+ setContentView(binding.getRoot())
+ binding.toolbar.backClickListener = { this.onBackPressed() }
+
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt
index 7dcb67d74..36b117ea0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt
@@ -1,5 +1,6 @@
package org.horizontal.tella.mobile.views.fragment.vault.adapters.connections
+import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
@@ -14,9 +15,12 @@ import org.horizontal.tella.mobile.views.fragment.vault.adapters.viewholders.bas
class ServerViewHolder(val view: View) : BaseViewHolder(view) {
private lateinit var reportTypeTextView: TextView
private lateinit var reportTypeImg: ImageView
+ private lateinit var twoLinesReportTypeTextView: TextView
+
override fun bind(item: ServerDataItem, vaultClickListener: VaultClickListener) {
reportTypeTextView = view.findViewById(R.id.server_name_textView)
+ twoLinesReportTypeTextView = view.findViewById(R.id.two_line_server_name_textView)
reportTypeImg = view.findViewById(R.id.server_img)
// Set the default padding
@@ -94,6 +98,16 @@ class ServerViewHolder(val view: View) : BaseViewHolder(view) {
)
)
}
+ ServerType.PEERTOPEER -> {
+ twoLinesReportTypeTextView.text = view.context.getText(R.string.NearBySharing)
+ reportTypeImg.setImageDrawable(
+ ResourcesCompat.getDrawable(
+ view.resources,
+ R.drawable.ic_share,
+ null
+ )
+ )
+ }
else -> { // todo create default server type
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt
index 4b1ba9d2a..4d6f5fd22 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt
@@ -463,6 +463,10 @@ class HomeVaultFragment : BaseFragment(), VaultClickListener {
nav().navigate(R.id.action_homeScreen_to_next_cloud_screen)
}
+ ServerType.PEERTOPEER -> {
+ nav().navigate(R.id.action_homeScreen_to_peerToPeer_screen)
+ }
+
else -> {}
}
}
@@ -745,6 +749,7 @@ class HomeVaultFragment : BaseFragment(), VaultClickListener {
* This function show connections when all the server types are counted.
**/
private fun maybeShowConnections() {
+ serversList?.add(ServerDataItem(ArrayList(), ServerType.PEERTOPEER))
// If the serversList is not empty, check if it has changed
if (serversList?.isEmpty() == false) {
// Use the vaultAdapter to check existing connections
diff --git a/mobile/src/main/res/drawable/ic_share.xml b/mobile/src/main/res/drawable/ic_share.xml
new file mode 100644
index 000000000..1938144ea
--- /dev/null
+++ b/mobile/src/main/res/drawable/ic_share.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/mobile/src/main/res/drawable/ic_share_big.xml b/mobile/src/main/res/drawable/ic_share_big.xml
new file mode 100644
index 000000000..fd3222f58
--- /dev/null
+++ b/mobile/src/main/res/drawable/ic_share_big.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/mobile/src/main/res/layout/activity_peer_to_peer.xml b/mobile/src/main/res/layout/activity_peer_to_peer.xml
new file mode 100644
index 000000000..098bc4fc4
--- /dev/null
+++ b/mobile/src/main/res/layout/activity_peer_to_peer.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/src/main/res/layout/item_home_vault_server.xml b/mobile/src/main/res/layout/item_home_vault_server.xml
index f216f9e01..a2fb5e027 100644
--- a/mobile/src/main/res/layout/item_home_vault_server.xml
+++ b/mobile/src/main/res/layout/item_home_vault_server.xml
@@ -1,5 +1,6 @@
-
-
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/server_name_textView"
+ tools:src="@drawable/ic_google_drive_white" />
-
+
-
-
+
-
\ No newline at end of file
+
diff --git a/mobile/src/main/res/layout/start_near_by_sharing_fragment.xml b/mobile/src/main/res/layout/start_near_by_sharing_fragment.xml
new file mode 100644
index 000000000..9de4a3bf7
--- /dev/null
+++ b/mobile/src/main/res/layout/start_near_by_sharing_fragment.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/navigation/home.xml b/mobile/src/main/res/navigation/home.xml
index 451360d73..1e1ca86f9 100644
--- a/mobile/src/main/res/navigation/home.xml
+++ b/mobile/src/main/res/navigation/home.xml
@@ -65,6 +65,11 @@
app:destination="@id/next_cloud_graph"
app:enterAnim="@anim/slide_in_start"
app:exitAnim="@anim/fade_out" />
+
+
+
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
new file mode 100644
index 000000000..df4dd7c20
--- /dev/null
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index ab332ec15..8132cdc06 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1003,4 +1003,15 @@ Would you like to share analytics with the Tella team?
Delete report?
Your report have successfully been submitted.
Attach file
+ Nearby sharing
+
+ Share files with nearby devices without an Internet connection\n 1. Both devices must be connected to the same Wifi network\n 2. Make sure you trust the person you are sharing files with
+
+ Send files
+ Receive files
+ Learn more about nearby sharing
+ Nearby sharing
+ How it works
+ https://tella-app.org/nearby-sharing/
+
From 0e0b53a79303b49ac181360e6e48242655cde2e3 Mon Sep 17 00:00:00 2001
From: wafa lakhal <4533152+wafalakhal@users.noreply.github.com>
Date: Wed, 21 May 2025 11:44:21 +0100
Subject: [PATCH 002/153] peerToPeer register and prepare upload implementation
(#375)
* WIP qr code design
* WIP qr code generation
* add dual text checkbox custom view
* WIP add show device info design
* WIP device info ligic
* WIP verification info design
* show device wifi hotspot
* wip complete hotspot logic/design
* add navigation to connect screen
* fix design
* fix design
* Fix hotspot name
* WIP generate certificate
* Fix certificate generation
* WIP generate code and start server
* Finish QrCode generation
* Finish scan and start qr code scanning
* add register endpoint logic in the server side
* change endpoint naming
* wip register from the sender side
* wip register api
* handle back button
* refactor code
* WIP code refactor
* wip implement prepare upload
* WIP refactor
* handle register response
* Fix serialization problem
* wip fix server issue
* Fix ktor parsin
* add file
* wip prepare upload handle happy path api
---------
Co-authored-by: Ahlem
---
build.gradle | 1 +
mobile/build.gradle | 16 +-
mobile/proguard-rules.pro | 5 +-
mobile/src/main/AndroidManifest.xml | 7 +-
mobile/src/main/assets/testDemo.txt | 1 +
.../tella/mobile/MyApplication.java | 18 +-
.../certificate/CertificateGenerator.kt | 68 ++++++
.../mobile/certificate/CertificateUtils.kt | 85 +++++++
.../tella/mobile/data/peertopeer/FileItem.kt | 12 +
.../data/peertopeer/PrepareUploadRequest.kt | 10 +
.../data/peertopeer/TellaPeerToPeerClient.kt | 183 +++++++++++++++
.../data/peertopeer/TellaPeerToPeerServer.kt | 138 +++++++++++
.../entity/peertopeer/DeviceMetadata.kt | 12 +
.../domain/entity/peertopeer/QRCodeInfos.kt | 15 ++
.../domain/peertopeer/KeyStoreConfig.kt | 26 +++
.../peertopeer/PeerConnectionPayload.kt | 18 ++
.../peertopeer/PeerPrepareUploadResponse.kt | 8 +
.../domain/peertopeer/PeerRegisterPayload.kt | 10 +
.../mobile/domain/peertopeer/PeerResponse.kt | 8 +
.../mobile/domain/peertopeer/TellaServer.kt | 7 +
.../tella/mobile/util/NavigationManager.kt | 19 +-
.../mobile/views/fragment/CameraFragment.kt | 42 ----
.../mobile/views/fragment/ReportsFragment.kt | 58 -----
.../peertopeer/PeerToPeerViewModel.kt | 220 ++++++++++++++++++
.../peertopeer/StartNearBySharingFragment.kt | 26 ++-
.../peertopeer/activity/PeerToPeerActivity.kt | 2 -
.../peertopeer/data/ConnectionType.kt | 5 +
.../fragment/peertopeer/data/NetWorkInfo.kt | 8 +
.../fragment/peertopeer/di/PeerModule.kt | 19 ++
.../receipentflow/ConnectHotspotFragment.kt | 83 +++++++
.../receipentflow/QRCodeFragment.kt | 89 +++++++
.../receipentflow/ShowDeviceInfoFragment.kt | 18 ++
.../receipentflow/VerificationInfoFragment.kt | 4 +
.../senderflow/ScanQrCodeFragment.kt | 111 +++++++++
.../mobile/views/settings/LanguageSettings.kt | 2 +-
mobile/src/main/res/drawable/icon_wifi.xml | 13 ++
.../src/main/res/drawable/qr_scan_border.xml | 10 +
.../main/res/layout/activity_peer_to_peer.xml | 22 +-
.../res/layout/connect_hotspot_layout.xml | 134 +++++++++++
.../src/main/res/layout/fragment_qr_code.xml | 91 ++++++++
mobile/src/main/res/layout/fragment_vault.xml | 1 +
.../main/res/layout/peer_to_peer_layout.xml | 8 +
.../main/res/layout/scan_qrcode_fragment.xml | 88 +++++++
.../res/layout/show_device_info_layout.xml | 113 +++++++++
.../layout/start_near_by_sharing_fragment.xml | 36 ++-
.../res/layout/verification_info_fragment.xml | 116 +++++++++
.../res/navigation/peer_to_peer_graph.xml | 38 ++-
mobile/src/main/res/values/strings.xml | 23 ++
.../shared_ui/buttons/DualTextCheckView.kt | 90 +++++++
.../hzontal/shared_ui/buttons/RoundButton.kt | 29 +--
.../main/res/drawable/bg_dual_text_check.xml | 16 ++
shared-ui/src/main/res/drawable/device.xml | 24 ++
.../res/layout-hdpi/information_button.xml | 4 +-
.../res/layout-xhdpi/information_button.xml | 4 +-
.../res/layout/dual_text_check_layout.xml | 53 +++++
shared-ui/src/main/res/values/attrs.xml | 7 +
shared-ui/src/main/res/values/styles.xml | 4 +
tella-keys/build.gradle | 5 +
.../tella/keys/key/LifecycleMainKey.java | 4 -
59 files changed, 2114 insertions(+), 173 deletions(-)
create mode 100644 mobile/src/main/assets/testDemo.txt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/DeviceMetadata.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/QRCodeInfos.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/KeyStoreConfig.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerResponse.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/TellaServer.kt
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/CameraFragment.kt
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/ReportsFragment.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
create mode 100644 mobile/src/main/res/drawable/icon_wifi.xml
create mode 100644 mobile/src/main/res/drawable/qr_scan_border.xml
create mode 100644 mobile/src/main/res/layout/connect_hotspot_layout.xml
create mode 100644 mobile/src/main/res/layout/fragment_qr_code.xml
create mode 100644 mobile/src/main/res/layout/peer_to_peer_layout.xml
create mode 100644 mobile/src/main/res/layout/scan_qrcode_fragment.xml
create mode 100644 mobile/src/main/res/layout/show_device_info_layout.xml
create mode 100644 mobile/src/main/res/layout/verification_info_fragment.xml
create mode 100644 shared-ui/src/main/java/org/hzontal/shared_ui/buttons/DualTextCheckView.kt
create mode 100644 shared-ui/src/main/res/drawable/bg_dual_text_check.xml
create mode 100644 shared-ui/src/main/res/drawable/device.xml
create mode 100644 shared-ui/src/main/res/layout/dual_text_check_layout.xml
diff --git a/build.gradle b/build.gradle
index fcee3f3e7..2bacd942a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -102,6 +102,7 @@ buildscript {
classpath "com.google.firebase:firebase-crashlytics-gradle:$versions.crashlyticsGradle"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.50'
+ classpath "org.jetbrains.kotlin:kotlin-serialization:$versions.kotlin"
}
}
diff --git a/mobile/build.gradle b/mobile/build.gradle
index e452de71a..29bb8a07c 100644
--- a/mobile/build.gradle
+++ b/mobile/build.gradle
@@ -5,6 +5,7 @@ plugins {
id 'dagger.hilt.android.plugin'
id 'com.google.firebase.crashlytics'
id 'com.google.gms.google-services'
+ id 'org.jetbrains.kotlin.plugin.serialization'
}
android {
@@ -88,7 +89,7 @@ android {
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
-
+ exclude 'META-INF/versions/9/OSGI-INF/MANIFEST.MF'
}
namespace 'org.horizontal.tella.mobile'
}
@@ -233,6 +234,19 @@ dependencies {
implementation "com.github.nextcloud-deps.hwsecurity:hwsecurity-fido:$versions.fidoVersion"
implementation "com.github.nextcloud-deps.hwsecurity:hwsecurity-fido2:$versions.fidoVersion"
+ //QR CODE SCAN/GENERATE LIBRARY
+ implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
+
+ //ktor imp
+ implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.9")
+ implementation("io.ktor:ktor-server-core:2.3.9")
+ implementation("io.ktor:ktor-server-netty:2.3.9")
+ implementation("io.ktor:ktor-server-content-negotiation:2.3.9")
+ implementation("io.ktor:ktor-server-cio:2.3.9")
+
+ implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3' // Use the latest version
+
+
}
def getLocalProperties() {
diff --git a/mobile/proguard-rules.pro b/mobile/proguard-rules.pro
index d114ab925..acb937b3a 100644
--- a/mobile/proguard-rules.pro
+++ b/mobile/proguard-rules.pro
@@ -246,4 +246,7 @@
-if class androidx.credentials.CredentialManager
-keep class androidx.credentials.playservices.** {
*;
-}
\ No newline at end of file
+}
+
+-keep class org.bouncycastle.** { *; }
+-dontwarn org.bouncycastle.**
\ No newline at end of file
diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml
index 6cc4674bf..428d36e0d 100644
--- a/mobile/src/main/AndroidManifest.xml
+++ b/mobile/src/main/AndroidManifest.xml
@@ -49,9 +49,9 @@
android:icon="@mipmap/tella_icon"
android:label="@string/app_name"
android:largeHeap="true"
+ android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/configure_localhost_media_file_http_server"
android:roundIcon="@mipmap/tella_icon_round"
- android:localeConfig="@xml/locales_config"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
@@ -701,6 +701,11 @@
+
+
\ No newline at end of file
diff --git a/mobile/src/main/assets/testDemo.txt b/mobile/src/main/assets/testDemo.txt
new file mode 100644
index 000000000..f6983e619
--- /dev/null
+++ b/mobile/src/main/assets/testDemo.txt
@@ -0,0 +1 @@
+ This is a test yo
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java b/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java
index 509ff254b..b7a6fc3d9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java
@@ -11,6 +11,7 @@
import android.os.Build;
import android.os.StrictMode;
import android.os.Bundle;
+import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -36,6 +37,7 @@
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.hzontal.shared_ui.data.CommonPrefs;
import org.conscrypt.Conscrypt;
@@ -53,6 +55,7 @@
import java.io.File;
import java.lang.ref.WeakReference;
import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
import java.security.Security;
import java.util.Arrays;
@@ -63,6 +66,7 @@
import dagger.hilt.android.HiltAndroidApp;
import io.reactivex.functions.Consumer;
import io.reactivex.plugins.RxJavaPlugins;
+
import org.horizontal.tella.mobile.bus.TellaBus;
import org.horizontal.tella.mobile.data.database.KeyDataSource;
import org.horizontal.tella.mobile.data.nextcloud.TempFileManager;
@@ -99,8 +103,6 @@ public class MyApplication extends MultiDexApplication implements IUnlockRegistr
Vault.Config vaultConfig;
private static final String TAG = MyApplication.class.getSimpleName();
public static final String DOT = ".";
- public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_17;
- private static WeakReference appContext;
private long startTime;
private long totalTimeSpent = 0; // Store total time spent in the app
private int activityReferences = 0;
@@ -235,6 +237,7 @@ public void accept(Throwable throwable) {
TellaKeysUI.initialize(mainKeyStore, mainKeyHolder, unlockRegistry, this, Preferences.getFailedUnlockOption(), Preferences.getUnlockRemainingAttempts(), Preferences.isShowUnlockRemainingAttempts());
insertConscrypt();
enableStrictMode();
+ setupBouncyCastleProvider();
}
private void configureCrashlytics() {
@@ -437,4 +440,15 @@ private void enableStrictMode() {
}
+ private void setupBouncyCastleProvider() {
+ try {
+ if (Security.getProvider("BC") == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ Timber.i("BouncyCastle provider registered");
+ }
+ } catch (Exception e) {
+ Timber.e(e, "Failed to register BouncyCastle provider");
+ }
+ }
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt
new file mode 100644
index 000000000..766bcd477
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt
@@ -0,0 +1,68 @@
+package org.horizontal.tella.mobile.certificate
+
+import org.bouncycastle.asn1.x500.X500Name
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
+import org.bouncycastle.jce.provider.BouncyCastleProvider
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
+import java.security.KeyPair
+import java.security.KeyPairGenerator
+import java.security.Security
+import java.security.cert.X509Certificate
+import java.util.Date
+
+object CertificateGenerator {
+
+ init {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(BouncyCastleProvider())
+ }
+ }
+
+ fun generateCertificate(
+ commonName: String = "Tella Android",
+ organization: String = "Tella",
+ validityDays: Int = 365,
+ ipAddress: String
+ ): Pair {
+ val keyGen = KeyPairGenerator.getInstance("RSA")
+ keyGen.initialize(2048)
+ val keyPair = keyGen.generateKeyPair()
+
+ val now = Date()
+ val validTo = Date(now.time + validityDays * 86400000L)
+
+ val issuer = X500Name("CN=$commonName,O=$organization")
+ val subject = issuer
+
+ val serialNumber = CertificateUtils.generateSerialNumber()
+
+ val certBuilder = JcaX509v3CertificateBuilder(
+ issuer, serialNumber, now, validTo, subject, keyPair.public
+ )
+
+ if (ipAddress.isNotEmpty()) {
+ val san = org.bouncycastle.asn1.x509.GeneralNames(
+ org.bouncycastle.asn1.x509.GeneralName(
+ org.bouncycastle.asn1.x509.GeneralName.iPAddress, ipAddress
+ )
+ )
+ certBuilder.addExtension(
+ org.bouncycastle.asn1.x509.Extension.subjectAlternativeName,
+ false,
+ san
+ )
+ }
+
+ val signer = JcaContentSignerBuilder("SHA256withRSA")
+ .build(keyPair.private)
+
+ val holder = certBuilder.build(signer)
+
+ val certificate = JcaX509CertificateConverter()
+ .getCertificate(holder)
+
+ return Pair(keyPair, certificate)
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
new file mode 100644
index 000000000..53cb67a5e
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
@@ -0,0 +1,85 @@
+package org.horizontal.tella.mobile.certificate
+
+import android.util.Base64
+import java.math.BigInteger
+import java.security.KeyPair
+import java.security.SecureRandom
+import java.security.cert.CertificateFactory
+import java.security.cert.X509Certificate
+import java.security.KeyStore
+import java.util.UUID
+import javax.net.ssl.KeyManagerFactory
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
+
+object CertificateUtils {
+
+ fun generateSerialNumber(): BigInteger {
+ return BigInteger(128, SecureRandom())
+ }
+
+ fun certificateToPem(certificate: X509Certificate): String {
+ val encoded = Base64.encodeToString(certificate.encoded, Base64.NO_WRAP)
+ return "-----BEGIN CERTIFICATE-----\n$encoded\n-----END CERTIFICATE-----"
+ }
+
+ fun pemToCertificate(pemString: String): X509Certificate {
+ val cleanPem = pemString
+ .replace("-----BEGIN CERTIFICATE-----", "")
+ .replace("-----END CERTIFICATE-----", "")
+ .replace("\\s".toRegex(), "")
+ val decoded = Base64.decode(cleanPem, Base64.DEFAULT)
+ val certFactory = CertificateFactory.getInstance("X.509")
+ return certFactory.generateCertificate(decoded.inputStream()) as X509Certificate
+ }
+
+ fun encodeBase64(data: ByteArray): String =
+ Base64.encodeToString(data, Base64.NO_WRAP)
+
+ fun decodeBase64(encodedString: String): ByteArray =
+ Base64.decode(encodedString, Base64.NO_WRAP)
+
+ fun getPublicKeyHash(certificate: X509Certificate): String {
+ val digest = java.security.MessageDigest.getInstance("SHA-256")
+ val hash = digest.digest(certificate.publicKey.encoded)
+ return hash.joinToString("") { "%02x".format(it) }
+ }
+
+ fun createSSLContext(
+ keyPair: KeyPair,
+ certificate: X509Certificate
+ ): SSLContext {
+ val keyStore = KeyStore.getInstance("PKCS12")
+ val keyPassword = UUID.randomUUID().toString()
+ keyStore.load(null, null)
+ keyStore.setKeyEntry(
+ "alias",
+ keyPair.private,
+ keyPassword.toCharArray(),
+ arrayOf(certificate)
+ )
+
+ val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
+ kmf.init(keyStore, keyPassword.toCharArray())
+
+ val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ tmf.init(keyStore)
+
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(kmf.keyManagers, tmf.trustManagers, SecureRandom())
+
+ return sslContext
+ }
+
+ fun getTrustManager(certificate: X509Certificate): X509TrustManager {
+ val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
+ keyStore.load(null, null)
+ keyStore.setCertificateEntry("alias", certificate)
+
+ val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ tmf.init(keyStore)
+
+ return tmf.trustManagers[0] as X509TrustManager
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
new file mode 100644
index 000000000..1c0d3c2dd
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
@@ -0,0 +1,12 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class FileItem(
+ val id: String,
+ val fileName: String,
+ val size: Long,
+ val fileType: String,
+ val sha256: String
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
new file mode 100644
index 000000000..e6e8b9aa8
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
@@ -0,0 +1,10 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class PrepareUploadRequest(
+ val title: String,
+ val sessionId: String,
+ val files: List
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
new file mode 100644
index 000000000..6345097b1
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -0,0 +1,183 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+import android.util.Log
+import kotlinx.serialization.encodeToString
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import kotlinx.serialization.json.Json
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
+import org.json.JSONObject
+import java.io.File
+import java.security.SecureRandom
+import java.security.cert.CertificateException
+import java.security.cert.X509Certificate
+import java.util.UUID
+import java.util.concurrent.TimeUnit
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManager
+import javax.net.ssl.X509TrustManager
+
+class TellaPeerToPeerClient {
+
+ private fun getClientWithFingerprintValidation(expectedFingerprint: String): OkHttpClient {
+ val trustManager = object : X509TrustManager {
+ override fun getAcceptedIssuers(): Array = arrayOf()
+
+ override fun checkClientTrusted(chain: Array, authType: String?) {}
+
+ override fun checkServerTrusted(chain: Array, authType: String?) {
+ val serverCert = chain[0]
+ val actualFingerprint = CertificateUtils.getPublicKeyHash(serverCert)
+
+ if (!actualFingerprint.equals(expectedFingerprint, ignoreCase = true)) {
+ throw CertificateException(
+ "Server certificate fingerprint mismatch.\nExpected: $expectedFingerprint\nGot: $actualFingerprint"
+ )
+ }
+ }
+ }
+
+ val sslContext = SSLContext.getInstance("TLS").apply {
+ init(null, arrayOf(trustManager), SecureRandom())
+ }
+
+ return OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .sslSocketFactory(sslContext.socketFactory, trustManager)
+ .build()
+ }
+
+ suspend fun registerPeerDevice(
+ ip: String,
+ port: String,
+ expectedFingerprint: String,
+ pin: String
+ ): Result = withContext(Dispatchers.IO) {
+ val url = "https://$ip:$port/api/v1/register"
+ Log.d("PeerClient", "Connecting to: $url")
+
+ try {
+ val payload = PeerRegisterPayload(
+ pin = pin,
+ nonce = UUID.randomUUID().toString()
+ )
+
+ val jsonPayload = Json.encodeToString(payload)
+ val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
+ Log.d("PeerClient", "Request payload: $requestBody")
+
+ val client = getClientWithFingerprintValidation(expectedFingerprint)
+ val request = Request.Builder()
+ .url(url)
+ .post(requestBody)
+ .addHeader("Content-Type", "application/json")
+ .build()
+
+ client.newCall(request).execute().use { response ->
+ if (!response.isSuccessful) {
+ val errorBody = response.body.string()
+ Log.e(
+ "PeerClient", """
+ HTTP ${response.code} Error
+ URL: $url
+ Headers: ${response.headers}
+ Body: $errorBody
+ """.trimIndent()
+ )
+ return@use Result.failure(Exception("HTTP ${response.code}: $errorBody"))
+ }
+
+ val contentType = response.header("Content-Type") ?: ""
+ if (!contentType.contains("application/json")) {
+ Log.w("PeerClient", "Unexpected Content-Type: $contentType")
+ }
+
+ val body = response.body?.string() ?: ""
+ return@use try {
+ val json = JSONObject(body)
+ Result.success(json.getString("sessionId"))
+ } catch (e: Exception) {
+ Result.failure(Exception("Invalid JSON response: ${e.message}"))
+ }
+ }
+ } catch (e: Exception) {
+ Log.e("PeerClient", "Request failed", e)
+ Result.failure(e)
+ }
+ }
+
+ suspend fun prepareUpload(
+ ip: String,
+ port: String,
+ expectedFingerprint: String,
+ title: String = "Title of the report",
+ file: File,
+ fileId: String,
+ sha256: String,
+ sessionId: String
+ ): Result {
+ return withContext(Dispatchers.IO) {
+ val url = "https://$ip:$port/api/v1/prepare-upload"
+
+ val fileItem = FileItem(
+ id = fileId,
+ fileName = file.name,
+ size = file.length(),
+ fileType = "application/octet-stream",
+ sha256 = sha256
+ )
+
+ val requestPayload = PrepareUploadRequest(
+ title = title,
+ sessionId = sessionId,
+ files = listOf(fileItem)
+ )
+
+ val jsonPayload = Json.encodeToString(requestPayload)
+ val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
+ Log.d("PeerClient", "Request payload: $requestBody")
+ val client = getClientWithFingerprintValidation(expectedFingerprint)
+
+ try {
+ val request = Request.Builder()
+ .url(url)
+ .post(requestBody)
+ .addHeader("Content-Type", "application/json")
+ .build()
+
+ client.newCall(request).execute().use { response ->
+ if (response.isSuccessful) {
+ val responseBody = response.body?.string()
+ responseBody?.let {
+ val jsonObject = JSONObject(it)
+ val transmissionId = jsonObject.getString("transmissionId")
+ Log.d("PrepareUpload", "Transmission ID: $transmissionId")
+ return@use Result.success(transmissionId)
+ }
+ } else {
+ Log.e("PrepareUpload", "Error ${response.code}: ${response.message}")
+ when (response.code) {
+ 409 -> {
+ Log.e("PrepareUpload", "Conflict: Try canceling active sessions.")
+ }
+
+ else -> {}
+ }
+ }
+ }
+ Result.failure(Exception("Unsuccessful response"))
+ } catch (e: Exception) {
+ Log.e("PrepareUpload", "Exception: ${e.message}", e)
+ Result.failure(e)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
new file mode 100644
index 000000000..3a56cb036
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -0,0 +1,138 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+import android.util.Log
+import com.google.gson.Gson
+import io.ktor.http.ContentType
+import io.ktor.http.HttpStatusCode
+import io.ktor.serialization.kotlinx.json.json
+import io.ktor.server.application.call
+import io.ktor.server.application.install
+import io.ktor.server.engine.ApplicationEngine
+import io.ktor.server.engine.applicationEngineEnvironment
+import io.ktor.server.engine.embeddedServer
+import io.ktor.server.engine.sslConnector
+import io.ktor.server.netty.Netty
+import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.server.request.receive
+import io.ktor.server.response.respond
+import io.ktor.server.response.respondText
+import io.ktor.server.routing.get
+import io.ktor.server.routing.post
+import io.ktor.server.routing.routing
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.put
+import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
+import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
+import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
+import org.horizontal.tella.mobile.domain.peertopeer.PeerResponse
+import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
+import java.security.KeyPair
+import java.security.KeyStore
+import java.security.cert.X509Certificate
+import java.util.UUID
+import kotlin.reflect.jvm.internal.impl.load.kotlin.JvmType
+
+const val port = 53317
+
+class TellaPeerToPeerServer(
+ private val ip: String,
+ private val serverPort: Int = port,
+ private val keyPair: KeyPair,
+ private val certificate: X509Certificate,
+ private val keyStoreConfig: KeyStoreConfig
+) : TellaServer {
+
+ private var engine: ApplicationEngine? = null
+
+ override val certificatePem: String
+ get() = CertificateUtils.certificateToPem(certificate)
+
+ override fun start() {
+ val keyStore = KeyStore.getInstance("PKCS12").apply {
+ load(null, null)
+ setKeyEntry(
+ keyStoreConfig.alias,
+ keyPair.private,
+ keyStoreConfig.password,
+ arrayOf(certificate)
+ )
+ }
+
+ engine = embeddedServer(Netty, environment = applicationEngineEnvironment {
+ sslConnector(
+ keyStore = keyStore,
+ keyAlias = keyStoreConfig.alias,
+ keyStorePassword = { keyStoreConfig.password },
+ privateKeyPassword = { keyStoreConfig.password }
+ ) {
+ this.host = ip
+ this.port = serverPort
+ }
+
+ module {
+ install(ContentNegotiation) {
+ json()
+ }
+ routing {
+ // Root route to confirm the server is running
+ get("/") {
+ Log.i("Test", "Server started")
+ call.respondText("The server is running securely over HTTPS.")
+ }
+
+ post("/api/v1/register") {
+ val request = try {
+ call.receive()
+ } catch (e: Exception) {
+ call.respondText(
+ """{"error": "Invalid request body"}""",
+ ContentType.Application.Json,
+ HttpStatusCode.BadRequest
+ )
+ return@post
+ }
+
+ val sessionId = UUID.randomUUID().toString()
+ call.respondText(
+ Gson().toJson(PeerResponse(sessionId)),
+ ContentType.Application.Json,
+ HttpStatusCode.OK
+ )
+ }
+
+
+ post("/api/v1/prepare-upload") {
+ val request = try {
+ call.receive()
+ } catch (e: Exception) {
+ call.respondText("Invalid body", status = HttpStatusCode.BadRequest)
+ return@post
+ }
+
+ if (request.title.isBlank() || request.sessionId.isBlank() || request.files.isEmpty()) {
+ call.respondText(
+ "Missing required fields",
+ status = HttpStatusCode.BadRequest
+ )
+ return@post
+ }
+
+ // we can process the files or store metadata here
+ val transmissionId = UUID.randomUUID().toString()
+ call.respondText(
+ Gson().toJson(PeerPrepareUploadResponse(transmissionId)),
+ ContentType.Application.Json,
+ HttpStatusCode.OK
+ )
+ }
+ }
+
+ }
+ }).start(wait = false)
+ }
+
+ override fun stop() {
+ engine?.stop(1000, 5000)
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/DeviceMetadata.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/DeviceMetadata.kt
new file mode 100644
index 000000000..90662f51a
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/DeviceMetadata.kt
@@ -0,0 +1,12 @@
+package org.horizontal.tella.mobile.domain.entity.peertopeer
+
+data class DeviceMetadata(
+ val deviceType: String = "mobile",
+ val version: String = "2.0",
+ val fingerprint: String,
+ val serverPort: Int = 53317,
+ val protocol: String = "https",
+ val download: Boolean = true,
+ val deviceModel: String = android.os.Build.MODEL ?: "Android",
+ val alias: String = "AndroidDevice"
+)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/QRCodeInfos.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/QRCodeInfos.kt
new file mode 100644
index 000000000..2a85a6eb7
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/QRCodeInfos.kt
@@ -0,0 +1,15 @@
+package org.horizontal.tella.mobile.domain.entity.peertopeer
+
+data class QRCodeInfos(
+ val ipAddress: String,
+ val pin: String,
+ val hash: String
+) {
+ override fun equals(other: Any?): Boolean {
+ return (other as? QRCodeInfos)?.ipAddress == ipAddress
+ }
+
+ override fun hashCode(): Int {
+ return ipAddress.hashCode()
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/KeyStoreConfig.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/KeyStoreConfig.kt
new file mode 100644
index 000000000..8d067c115
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/KeyStoreConfig.kt
@@ -0,0 +1,26 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+import java.util.UUID
+
+data class KeyStoreConfig(
+ val alias: String = "tella-alias",
+ val password: CharArray = UUID.randomUUID().toString().toCharArray()
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as KeyStoreConfig
+
+ if (alias != other.alias) return false
+ if (!password.contentEquals(other.password)) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = alias.hashCode()
+ result = 31 * result + password.contentHashCode()
+ return result
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
new file mode 100644
index 000000000..7a28595c5
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
@@ -0,0 +1,18 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+import com.google.gson.annotations.SerializedName
+
+data class PeerConnectionPayload(
+ @SerializedName("connect_code")
+ val connectCode: String,
+
+ @SerializedName("port")
+ val port: Int,
+
+ @SerializedName("certificate_hash")
+ val certificateHash: String,
+
+ @SerializedName("pin")
+ val pin: String
+)
+
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
new file mode 100644
index 000000000..acfc25782
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
@@ -0,0 +1,8 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class PeerPrepareUploadResponse(
+ val transmissionId: String
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
new file mode 100644
index 000000000..d9c399056
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
@@ -0,0 +1,10 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+import kotlinx.serialization.Serializable
+import java.util.UUID
+
+@Serializable
+data class PeerRegisterPayload(
+ val pin: String,
+ val nonce: String = UUID.randomUUID().toString()
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerResponse.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerResponse.kt
new file mode 100644
index 000000000..9891126b7
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerResponse.kt
@@ -0,0 +1,8 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class PeerResponse(
+ val sessionId: String
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/TellaServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/TellaServer.kt
new file mode 100644
index 000000000..655edf426
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/TellaServer.kt
@@ -0,0 +1,7 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+interface TellaServer {
+ fun start()
+ fun stop()
+ val certificatePem: String
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index f6ffc4a05..a69026b15 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -55,9 +55,11 @@ class NavigationManager(
fun navigateFromGoogleDriveEntryScreenToGoogleDriveSendScreen() {
navigateToWithBundle(R.id.action_newGoogleDriveScreen_to_googleDriveSendScreen)
}
+
fun navigateFromNextCloudEntryScreenToNextCloudSendScreen() {
navigateToWithBundle(R.id.action_newNextCloudScreen_to_nextCloudSendScreen)
}
+
fun navigateFromGoogleDriveMainScreenToGoogleDriveSendScreen() {
navigateToWithBundle(R.id.action_googleDriveScreen_to_googleDriveSendScreen)
}
@@ -65,6 +67,7 @@ class NavigationManager(
fun navigateFromNextCloudMainScreenToNextCloudSendScreen() {
navigateToWithBundle(R.id.action_nextCloudScreen_to_nextCloudSendScreen)
}
+
fun navigateFromGoogleDriveScreenToGoogleDriveSubmittedScreen() {
navigateToWithBundle(R.id.action_googleDriveScreen_to_googleDriveSubmittedScreen)
}
@@ -72,6 +75,7 @@ class NavigationManager(
fun navigateFromNextCloudScreenToNextCloudSubmittedScreen() {
navigateToWithBundle(R.id.action_nextCloudScreen_to_nextCloudSubmittedScreen)
}
+
fun navigateFromDropBoxScreenToDropBoxSubmittedScreen() {
navigateToWithBundle(R.id.action_dropBoxScreen_to_dropBoxSubmittedScreen)
}
@@ -136,7 +140,8 @@ class NavigationManager(
fun navigateToNextCloudCreateFolderScreen() {
navigateToWithBundle(R.id.action_loginNextCloudScreen_to_nextCloudNewFolderScreen)
}
- fun actionNextCloudNewFolderScreenToSuccessfulScreen(){
+
+ fun actionNextCloudNewFolderScreenToSuccessfulScreen() {
navigateToWithBundle(R.id.action_nextCloudNewFolderScreen_to_successfulSetServerFragment)
}
@@ -160,4 +165,16 @@ class NavigationManager(
navigateToWithBundle(R.id.action_selectSharedDriveFragment_to_googleDriveConnectedServerFragment)
}
+ fun navigateFromStartNearBySharingFragmentToConnectHotspotFragment() {
+ navigateToWithBundle(R.id.action_startNearBySharingFragment_to_connectHotspotFragment)
+ }
+
+ fun navigateFromActionConnectHotspotScreenToQrCodeScreen() {
+ navigateToWithBundle(R.id.action_connectHotspotScreen_to_qrCodeScreen)
+ }
+
+ fun navigateFromActionConnectHotspotScreenToScanQrCodeScreen() {
+ navigateToWithBundle(R.id.action_startNearBySharingFragment_to_scanQrCodeScreen)
+ }
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/CameraFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/CameraFragment.kt
deleted file mode 100644
index 7aa74f02c..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/CameraFragment.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.horizontal.tella.mobile.views.fragment
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import org.horizontal.tella.mobile.R
-
-// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
-private const val ARG_PARAM1 = "param1"
-private const val ARG_PARAM2 = "param2"
-
-class CameraFragment : Fragment() {
- private var param1: String? = null
- private var param2: String? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- arguments?.let {
- param1 = it.getString(ARG_PARAM1)
- param2 = it.getString(ARG_PARAM2)
- }
- }
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?): View? {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.fragment_camera, container, false)
- }
-
- companion object {
- @JvmStatic
- fun newInstance(param1: String, param2: String) =
- CameraFragment().apply {
- arguments = Bundle().apply {
- putString(ARG_PARAM1, param1)
- putString(ARG_PARAM2, param2)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/ReportsFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/ReportsFragment.kt
deleted file mode 100644
index b604058d5..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/ReportsFragment.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.horizontal.tella.mobile.views.fragment
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import org.horizontal.tella.mobile.R
-
-// TODO: Rename parameter arguments, choose names that match
-// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
-private const val ARG_PARAM1 = "param1"
-private const val ARG_PARAM2 = "param2"
-
-/**
- * A simple [Fragment] subclass.
- * Use the [ReportsFragment.newInstance] factory method to
- * create an instance of this fragment.
- */
-class ReportsFragment : Fragment() {
- // TODO: Rename and change types of parameters
- private var param1: String? = null
- private var param2: String? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- arguments?.let {
- param1 = it.getString(ARG_PARAM1)
- param2 = it.getString(ARG_PARAM2)
- }
- }
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?): View? {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.fragment_reports, container, false)
- }
-
- companion object {
- /**
- * Use this factory method to create a new instance of
- * this fragment using the provided parameters.
- *
- * @param param1 Parameter 1.
- * @param param2 Parameter 2.
- * @return A new instance of fragment ReportsFragment.
- */
- // TODO: Rename and change types and number of parameters
- @JvmStatic
- fun newInstance(param1: String, param2: String) =
- ReportsFragment().apply {
- arguments = Bundle().apply {
- putString(ARG_PARAM1, param1)
- putString(ARG_PARAM2, param2)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
new file mode 100644
index 000000000..9faa3cb48
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -0,0 +1,220 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import android.net.wifi.WifiInfo
+import android.net.wifi.WifiManager
+import android.os.Build
+import android.text.format.Formatter
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
+import org.horizontal.tella.mobile.views.fragment.peertopeer.data.NetworkInfo
+import org.json.JSONArray
+import org.json.JSONObject
+import java.io.File
+import java.io.FileOutputStream
+import java.net.Inet4Address
+import java.net.NetworkInterface
+import java.security.MessageDigest
+import java.security.SecureRandom
+import java.security.cert.CertificateException
+import java.security.cert.X509Certificate
+import java.util.UUID
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManager
+import javax.net.ssl.X509TrustManager
+
+@HiltViewModel
+class PeerToPeerViewModel @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val peerClient: TellaPeerToPeerClient
+) :
+ ViewModel() {
+
+ private val _networkInfo = MutableLiveData()
+ val networkInfo: LiveData = _networkInfo
+ var currentNetworkInfo: NetworkInfo? = null
+ private set
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ @SuppressLint("MissingPermission", "DiscouragedPrivateApi")
+ fun fetchCurrentNetworkInfo() {
+ val connectivityManager =
+ ContextCompat.getSystemService(context, ConnectivityManager::class.java)
+ val network = connectivityManager?.activeNetwork
+ val capabilities = connectivityManager?.getNetworkCapabilities(network)
+
+ when {
+ capabilities == null -> {
+ _networkInfo.value = NetworkInfo(ConnectionType.NONE, null, null)
+ }
+
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
+ val wifiManager =
+ context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ val wifiInfo = wifiManager.connectionInfo
+
+ val ssid =
+ if (!wifiInfo.ssid.isNullOrEmpty() && wifiInfo.ssid != WifiManager.UNKNOWN_SSID) {
+ wifiInfo.ssid.trim('"')
+ } else {
+ getWifiSsidFromCapabilities(capabilities) ?: "Hotspot"
+ }
+
+ val ipAddress = Formatter.formatIpAddress(wifiInfo.ipAddress)
+ _networkInfo.value = NetworkInfo(ConnectionType.WIFI, ssid, ipAddress)
+ }
+
+ isDeviceHotspotEnabled(context) -> {
+ val hotspotSSID = getDeviceHotspotSSID(context) ?: "Hotspot"
+ val hotspotIpAddress = getDeviceHotspotIpAddress()
+ _networkInfo.value =
+ NetworkInfo(ConnectionType.HOTSPOT, hotspotSSID, hotspotIpAddress)
+ }
+
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
+ _networkInfo.value = NetworkInfo(ConnectionType.CELLULAR, null, null)
+ }
+
+ else -> {
+ _networkInfo.value = NetworkInfo(ConnectionType.NONE, null, null)
+ }
+ }
+
+
+ currentNetworkInfo = _networkInfo.value
+ }
+
+ @SuppressLint("DiscouragedPrivateApi")
+ private fun getDeviceHotspotSSID(context: Context): String? {
+ return try {
+ val wifiManager =
+ context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ val method = wifiManager.javaClass.getDeclaredMethod("getWifiApConfiguration")
+ method.isAccessible = true
+ val wifiConfig = method.invoke(wifiManager)
+ wifiConfig?.let {
+ val ssidField = it.javaClass.getDeclaredField("SSID")
+ ssidField.isAccessible = true
+ (ssidField.get(it) as? String)?.trim('"')
+ }
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ @SuppressLint("DiscouragedPrivateApi")
+ private fun isDeviceHotspotEnabled(context: Context): Boolean {
+ return try {
+ val wifiManager =
+ context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ val method = wifiManager.javaClass.getDeclaredMethod("isWifiApEnabled")
+ method.isAccessible = true
+ method.invoke(wifiManager) as Boolean
+ } catch (e: Exception) {
+ false
+ }
+ }
+
+ private fun getWifiSsidFromCapabilities(capabilities: NetworkCapabilities): String? {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ (capabilities.transportInfo as? WifiInfo)?.ssid?.trim('"')
+ } else {
+ null
+ }
+ }
+
+ @SuppressLint("DiscouragedPrivateApi")
+ private fun getDeviceHotspotIpAddress(): String? {
+ return try {
+ val networkInterfaces = NetworkInterface.getNetworkInterfaces()
+ networkInterfaces.iterator().forEach { networkInterface ->
+ networkInterface.inetAddresses.iterator().forEach { inetAddress ->
+ if (!inetAddress.isLoopbackAddress && inetAddress is Inet4Address) {
+ if (networkInterface.displayName.contains("wlan") || networkInterface.displayName.contains(
+ "ap"
+ )
+ ) {
+ return inetAddress.hostAddress
+ }
+ }
+ }
+ }
+ null
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ fun onQrCodeParsed(ip: String, port: String, hash: String, pin: String) {
+ viewModelScope.launch {
+ val result = peerClient.registerPeerDevice(ip, port, hash, pin)
+ result.onSuccess {
+ Log.d("QRCode", "Registered successfully: $it")
+ val file = createFileFromAsset(context, "testDemo.txt")
+ peerClient.prepareUpload(ip,port,hash,"test report",file,UUID.randomUUID().toString(),calculateSha256(file),UUID.randomUUID().toString())
+ // update UI state
+ }.onFailure {
+ Log.e("QRCode", "Registration failed: ${it.message}")
+ // handle error (maybe post a value to LiveData)
+ }
+ }
+ }
+
+
+ private fun createFileFromAsset(context: Context, assetFileName: String): File {
+ // Create a temporary file in the cache directory
+ val tempFile = File(context.cacheDir, assetFileName)
+
+ if (!tempFile.exists()) {
+ Log.e("PrepareUpload", "File does not exist: ${tempFile.absolutePath}")
+ }
+
+ // Open the asset file
+ context.assets.open(assetFileName).use { inputStream ->
+ // Write the content of the asset to the temporary file
+ FileOutputStream(tempFile).use { outputStream ->
+ inputStream.copyTo(outputStream)
+ }
+ }
+
+ return tempFile
+ }
+
+
+
+ private fun calculateSha256(file: File): String {
+ val digest = MessageDigest.getInstance("SHA-256")
+ file.inputStream().use { input ->
+ val buffer = ByteArray(8192)
+ var bytesRead: Int
+ while (input.read(buffer).also { bytesRead = it } != -1) {
+ digest.update(buffer, 0, bytesRead)
+ }
+ }
+ return digest.digest().joinToString("") { "%02x".format(it) }
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt
index 3ebe4c6e7..558712df8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/StartNearBySharingFragment.kt
@@ -2,11 +2,10 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import android.os.Bundle
import android.view.View
-import androidx.core.view.isVisible
+import com.hzontal.tella_locking_ui.ui.pin.pinview.ResourceUtils.getColor
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.StartNearBySharingFragmentBinding
import org.horizontal.tella.mobile.util.Util
-import org.horizontal.tella.mobile.util.hide
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
class StartNearBySharingFragment : BaseBindingFragment(
@@ -19,9 +18,9 @@ class StartNearBySharingFragment : BaseBindingFragment navManager().navigateFromActionConnectHotspotScreenToScanQrCodeScreen()
+ receiveFilesBtn.isChecked -> navManager().navigateFromStartNearBySharingFragmentToConnectHotspotFragment()
+ else -> {}
+ }
+ }
}
-
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
index 81f8f350c..c44c043b7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
@@ -11,7 +11,5 @@ class PeerToPeerActivity : BaseLockActivity() {
super.onCreate(savedInstanceState)
binding = ActivityPeerToPeerBinding.inflate(layoutInflater)
setContentView(binding.getRoot())
- binding.toolbar.backClickListener = { this.onBackPressed() }
-
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt
new file mode 100644
index 000000000..4cca5a3b9
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt
@@ -0,0 +1,5 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.data
+
+enum class ConnectionType {
+ WIFI, CELLULAR, HOTSPOT, NONE
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt
new file mode 100644
index 000000000..ffaf84136
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt
@@ -0,0 +1,8 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.data
+
+data class NetworkInfo(
+ val type: ConnectionType,
+ val networkName: String?,
+ val ipAddress: String?,
+ var port: String = "53317"
+)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
new file mode 100644
index 000000000..fefe59992
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
@@ -0,0 +1,19 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.di
+
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object PeerModule {
+
+ @Provides
+ @Singleton
+ fun providePeerClient(): TellaPeerToPeerClient {
+ return TellaPeerToPeerClient()
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
new file mode 100644
index 000000000..ecd84c81c
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -0,0 +1,83 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.activityViewModels
+import com.hzontal.tella_locking_ui.ui.pin.pinview.ResourceUtils.getColor
+import dagger.hilt.android.AndroidEntryPoint
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.databinding.ConnectHotspotLayoutBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
+
+@AndroidEntryPoint
+class ConnectHotspotFragment :
+ BaseBindingFragment(ConnectHotspotLayoutBinding::inflate) {
+
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
+ private var isCheckboxChecked = false
+
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initObservers()
+ initListeners()
+ viewModel.fetchCurrentNetworkInfo()
+ }
+
+ private fun initObservers() {
+
+ viewModel.networkInfo.observe(viewLifecycleOwner) { info ->
+ when (info.type) {
+ ConnectionType.HOTSPOT, ConnectionType.WIFI, ConnectionType.CELLULAR -> {
+ binding.currentWifiText.setRightText(info.networkName)
+ updateNextButtonState(ConnectionType.HOTSPOT)
+ }
+
+ ConnectionType.NONE -> {
+ binding.currentWifiText.setRightText("No network connected")
+ updateNextButtonState(ConnectionType.NONE)
+ }
+ }
+ }
+ }
+
+ private fun initListeners() {
+
+ binding.currentWifi.setOnCheckedChangeListener { isChecked ->
+ isCheckboxChecked = isChecked
+ updateNextButtonState(viewModel.currentNetworkInfo?.type)
+ }
+
+ binding.toolbar.backClickListener = { baseActivity.onBackPressed() }
+
+ binding.nextBtn.setOnClickListener { }
+
+ binding.backBtn.setOnClickListener { baseActivity.onBackPressed() }
+ }
+
+ private fun updateNextButtonState(connectionType: ConnectionType?) {
+ val isEligibleConnection =
+ connectionType != ConnectionType.NONE && connectionType != ConnectionType.CELLULAR
+ val shouldEnable = isEligibleConnection && isCheckboxChecked
+
+ binding.nextBtn.setOnClickListener(if (shouldEnable) {
+ { onNextClicked() }
+ } else {
+ { }
+ })
+ binding.nextBtn.setTextColor(
+ getColor(baseActivity, if (shouldEnable) R.color.wa_white else R.color.wa_white_40)
+ )
+ binding.currentWifi.setCheckboxEnabled(isEligibleConnection)
+ }
+
+ private fun onNextClicked() {
+ navManager().navigateFromActionConnectHotspotScreenToQrCodeScreen()
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
new file mode 100644
index 000000000..229783d68
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -0,0 +1,89 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+import android.graphics.Bitmap
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.activityViewModels
+import com.google.gson.Gson
+import com.google.zxing.BarcodeFormat
+import com.google.zxing.WriterException
+import com.journeyapps.barcodescanner.BarcodeEncoder
+import org.horizontal.tella.mobile.certificate.CertificateGenerator
+import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
+import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerServer
+import org.horizontal.tella.mobile.data.peertopeer.port
+import org.horizontal.tella.mobile.databinding.FragmentQrCodeBinding
+import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
+import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+
+class QRCodeFragment : BaseBindingFragment(FragmentQrCodeBinding::inflate) {
+
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
+ private var server: TellaServer? = null
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val ip = viewModel.currentNetworkInfo?.ipAddress
+ if (!ip.isNullOrEmpty()) {
+ setupServerAndQr(ip)
+ }
+ handleBack()
+ }
+
+ private fun setupServerAndQr(ip: String) {
+ val (keyPair, certificate) = CertificateGenerator.generateCertificate(ipAddress = ip)
+ val config = KeyStoreConfig()
+
+ server = TellaPeerToPeerServer(
+ ip = ip,
+ keyPair = keyPair,
+ certificate = certificate,
+ keyStoreConfig = config
+ )
+ server?.start()
+
+ val certHash = CertificateUtils.getPublicKeyHash(certificate)
+ val pin = "111111"
+ val port = port
+
+ val payload = PeerConnectionPayload(
+ connectCode = ip,
+ port = port,
+ certificateHash = certHash,
+ pin = pin
+ )
+
+ val qrPayload = Gson().toJson(payload)
+ generateQrCode(qrPayload)
+ }
+
+
+ private fun generateQrCode(content: String) {
+ try {
+ val barcodeEncoder = BarcodeEncoder()
+ val bitmap: Bitmap = barcodeEncoder.encodeBitmap(
+ content,
+ BarcodeFormat.QR_CODE,
+ 600,
+ 600
+ )
+ binding.qrCodeImageView.setImageBitmap(bitmap)
+ } catch (e: WriterException) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun handleBack() {
+ binding.toolbar.backClickListener = { nav().popBackStack() }
+ binding.backBtn.setOnClickListener { nav().popBackStack() }
+ }
+
+ // TODO NEXT STEPS
+ //TODO WORK ON THE SENDER RESPONER
+ // TODO PREAPRE REGISTER RESPONE
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
new file mode 100644
index 000000000..698da492d
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -0,0 +1,18 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+import android.os.Bundle
+import android.view.View
+import org.horizontal.tella.mobile.databinding.ShowDeviceInfoLayoutBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+
+class ShowDeviceInfoFragment : BaseBindingFragment(ShowDeviceInfoLayoutBinding::inflate) {
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initListeners()
+ }
+
+ private fun initListeners() {
+
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt
new file mode 100644
index 000000000..5af7e3916
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt
@@ -0,0 +1,4 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+class VerificationInfoFragment {
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
new file mode 100644
index 000000000..64a36f774
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -0,0 +1,111 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
+
+import android.Manifest
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.activityViewModels
+import com.google.gson.Gson
+import com.journeyapps.barcodescanner.BarcodeCallback
+import com.journeyapps.barcodescanner.BarcodeResult
+import com.journeyapps.barcodescanner.CompoundBarcodeView
+import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
+import org.horizontal.tella.mobile.databinding.ScanQrcodeFragmentBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+
+class ScanQrCodeFragment :
+ BaseBindingFragment(ScanQrcodeFragmentBinding::inflate) {
+
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
+ private lateinit var barcodeView: CompoundBarcodeView
+
+ companion object {
+ private const val CAMERA_REQUEST_CODE = 1001
+ }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ barcodeView = CompoundBarcodeView(requireContext())
+ barcodeView = binding.qrCodeScanView
+
+ if (ContextCompat.checkSelfPermission(
+ requireContext(),
+ Manifest.permission.CAMERA
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ startScanning()
+ } else {
+ baseActivity.maybeChangeTemporaryTimeout {
+ requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_REQUEST_CODE)
+ }
+ }
+ handleBack()
+ }
+
+ private fun startScanning() {
+ barcodeView.decodeContinuous(object : BarcodeCallback {
+
+ override fun barcodeResult(result: BarcodeResult?) {
+ result?.text?.let { qrContent ->
+ barcodeView.pause()
+
+ try {
+ val payload = Gson().fromJson(qrContent, PeerConnectionPayload::class.java)
+
+ viewModel.onQrCodeParsed(
+ ip = payload.connectCode,
+ port = payload.port.toString(),
+ hash = payload.certificateHash,
+ pin = payload.pin
+ )
+
+ } catch (e: Exception) {
+ e.printStackTrace()
+ // Show a message: Invalid QR Code
+ }
+ }
+ }
+
+
+ override fun possibleResultPoints(resultPoints: MutableList?) {
+ }
+ })
+
+ barcodeView.resume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ barcodeView.pause()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ barcodeView.resume()
+ }
+
+ override fun onDestroyView() {
+ barcodeView.pauseAndWait()
+ super.onDestroyView()
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int, permissions: Array, grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == CAMERA_REQUEST_CODE && grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) {
+ startScanning()
+ }
+ }
+
+ private fun handleBack() {
+ binding.toolbar.backClickListener = { nav().popBackStack() }
+ binding.backBtn.setOnClickListener { nav().popBackStack() }
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/settings/LanguageSettings.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/settings/LanguageSettings.kt
index 015e0d738..e166126d6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/settings/LanguageSettings.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/settings/LanguageSettings.kt
@@ -49,7 +49,7 @@ class LanguageSettings : BaseFragment(), View.OnClickListener {
private fun createLangViews() {
if (languages.isEmpty()) {
languages =
- ArrayList(Arrays.asList(*resources.getStringArray(R.array.ra_lang_codes)))
+ ArrayList(listOf(*resources.getStringArray(R.array.ra_lang_codes)))
languages.add(0, null)
val prefferedLang = LocaleManager.getInstance().languageSetting
diff --git a/mobile/src/main/res/drawable/icon_wifi.xml b/mobile/src/main/res/drawable/icon_wifi.xml
new file mode 100644
index 000000000..79f46f896
--- /dev/null
+++ b/mobile/src/main/res/drawable/icon_wifi.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/mobile/src/main/res/drawable/qr_scan_border.xml b/mobile/src/main/res/drawable/qr_scan_border.xml
new file mode 100644
index 000000000..2ef2efe84
--- /dev/null
+++ b/mobile/src/main/res/drawable/qr_scan_border.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/activity_peer_to_peer.xml b/mobile/src/main/res/layout/activity_peer_to_peer.xml
index 098bc4fc4..06985463c 100644
--- a/mobile/src/main/res/layout/activity_peer_to_peer.xml
+++ b/mobile/src/main/res/layout/activity_peer_to_peer.xml
@@ -9,35 +9,15 @@
android:textDirection="locale"
tools:context="org.horizontal.tella.mobile.views.fragment.peertopeer.activity.PeerToPeerActivity">
-
-
-
-
-
-
+
diff --git a/mobile/src/main/res/layout/connect_hotspot_layout.xml b/mobile/src/main/res/layout/connect_hotspot_layout.xml
new file mode 100644
index 000000000..171c2009e
--- /dev/null
+++ b/mobile/src/main/res/layout/connect_hotspot_layout.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/fragment_qr_code.xml b/mobile/src/main/res/layout/fragment_qr_code.xml
new file mode 100644
index 000000000..26a86698e
--- /dev/null
+++ b/mobile/src/main/res/layout/fragment_qr_code.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/src/main/res/layout/fragment_vault.xml b/mobile/src/main/res/layout/fragment_vault.xml
index e8e67a2d3..327e0c814 100644
--- a/mobile/src/main/res/layout/fragment_vault.xml
+++ b/mobile/src/main/res/layout/fragment_vault.xml
@@ -5,6 +5,7 @@
android:layout_height="match_parent"
android:background="@color/space_cadet"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/root"
>
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/scan_qrcode_fragment.xml b/mobile/src/main/res/layout/scan_qrcode_fragment.xml
new file mode 100644
index 000000000..8e7336bcf
--- /dev/null
+++ b/mobile/src/main/res/layout/scan_qrcode_fragment.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/src/main/res/layout/show_device_info_layout.xml b/mobile/src/main/res/layout/show_device_info_layout.xml
new file mode 100644
index 000000000..f850f652d
--- /dev/null
+++ b/mobile/src/main/res/layout/show_device_info_layout.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/start_near_by_sharing_fragment.xml b/mobile/src/main/res/layout/start_near_by_sharing_fragment.xml
index 9de4a3bf7..24a6169f6 100644
--- a/mobile/src/main/res/layout/start_near_by_sharing_fragment.xml
+++ b/mobile/src/main/res/layout/start_near_by_sharing_fragment.xml
@@ -1,10 +1,28 @@
+
+
+
+
+
@@ -63,8 +82,10 @@
android:layout_marginTop="12dp"
android:gravity="center"
app:check_state="false"
+ app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintTop_toBottomOf="@+id/sendFilesBtn"
- app:text="@string/receive_files" />
+ app:text="@string/receive_files"
+ tools:layout_editor_absoluteX="24dp" />
diff --git a/mobile/src/main/res/layout/verification_info_fragment.xml b/mobile/src/main/res/layout/verification_info_fragment.xml
new file mode 100644
index 000000000..a8c269056
--- /dev/null
+++ b/mobile/src/main/res/layout/verification_info_fragment.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index df4dd7c20..ed48fc285 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -8,6 +8,40 @@
+ android:label="StartNearBySharingFragment"
+ tools:layout="@layout/start_near_by_sharing_fragment">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index 8132cdc06..fbc7fb6db 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1003,6 +1003,29 @@ Would you like to share analytics with the Tella team?
Delete report?
Your report have successfully been submitted.
Attach file
+ Connect to device
+ Show this QR code for the sender to scan
+ Scan the recipient’s QR code
+ Having trouble with the QR code?
+ Connect manually
+ Show your device information
+ The sender needs to input the following to\n connect to your device.
+ Connect code
+ PIN
+ Port
+ Verification
+ Make sure that this sequence matches what is shown on the sender’s device.
+ If the sequence on your device does not match the sequence on the sender’s device, the connection may not be secure and should be discarded.
+ Confirm and connect
+ Discard and start over
+ Wi-Fi
+ Get connected
+ Make sure both devices are connected to the same Wi-Fi network
+ Tips to connect\n1. The Wi-Fi network does not need to be \nconnected to the internet.\n2.
+You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
+3. Disable any VPN connections.
+ Current Wifi network
+ Yes, we are on the same Wi-Fi network
Nearby sharing
Share files with nearby devices without an Internet connection\n 1. Both devices must be connected to the same Wifi network\n 2. Make sure you trust the person you are sharing files with
diff --git a/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/DualTextCheckView.kt b/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/DualTextCheckView.kt
new file mode 100644
index 000000000..9dfd63788
--- /dev/null
+++ b/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/DualTextCheckView.kt
@@ -0,0 +1,90 @@
+package org.hzontal.shared_ui.buttons
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import androidx.annotation.StringRes
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.isVisible
+import org.hzontal.shared_ui.R
+import org.hzontal.shared_ui.databinding.DualTextCheckLayoutBinding
+
+class DualTextCheckView @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr) {
+
+ @StringRes
+ private var rightTextRes: Int = -1
+
+ @StringRes
+ private var leftTextRes: Int = -1
+
+ private var isCheckboxVisible: Boolean = false
+
+
+ private val binding: DualTextCheckLayoutBinding =
+ DualTextCheckLayoutBinding.inflate(LayoutInflater.from(context), this, true)
+
+ private var onCheckedChangeListener: ((Boolean) -> Unit)? = null
+
+ fun setOnCheckedChangeListener(listener: (Boolean) -> Unit) {
+ this.onCheckedChangeListener = listener
+ }
+
+
+ init {
+ initListeners()
+ extractAttributes(attrs, defStyleAttr)
+ }
+
+ private fun extractAttributes(attrs: AttributeSet?, defStyleAttr: Int) {
+ attrs?.let {
+ val typedArray = context.obtainStyledAttributes(
+ attrs, R.styleable.DualTextCheckView, defStyleAttr, defStyleAttr
+ )
+
+ try {
+ rightTextRes = typedArray.getResourceId(R.styleable.DualTextCheckView_rightText, -1)
+ leftTextRes = typedArray.getResourceId(R.styleable.DualTextCheckView_leftText, -1)
+ isCheckboxVisible =
+ typedArray.getBoolean(R.styleable.DualTextCheckView_checkboxVisible, false)
+
+ } finally {
+ typedArray.recycle()
+ }
+ }
+ bindView()
+ }
+
+ private fun bindView() {
+ if (rightTextRes != -1) {
+ binding.rightTextView.setText(rightTextRes)
+ }
+ if (leftTextRes != -1) {
+ binding.leftTextView.setText(leftTextRes)
+ }
+ binding.checkBox.isVisible = isCheckboxVisible
+ }
+
+
+ private fun initListeners() {
+ binding.checkBox.setOnCheckedChangeListener { _, isChecked ->
+ onCheckedChangeListener?.invoke(isChecked)
+ }
+ }
+
+ fun setRightText(text : String?){
+ if (text != null){
+ binding.rightTextView.text = text
+ }
+ }
+
+ // New method: Enable/Disable Checkbox
+ fun setCheckboxEnabled(isEnabled: Boolean) {
+ binding.checkBox.isEnabled = isEnabled
+ binding.rightTextView.isEnabled = isEnabled
+ binding.leftTextView.isEnabled = isEnabled
+ alpha = if (isEnabled) 1f else 0.5f // visually indicate disabled state
+ }
+
+}
\ No newline at end of file
diff --git a/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt b/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt
index 2669a16e9..075bc0200 100644
--- a/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt
+++ b/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt
@@ -15,15 +15,14 @@ import org.hzontal.shared_ui.R
import org.hzontal.shared_ui.databinding.LayoutRoundButtonBinding
class RoundButton @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), Checkable {
@StringRes
private var text: Int = -1
private var tintColor: Int = -1
private var textColor: Int = -1
+ private var isTextAllCaps = false
private val binding: LayoutRoundButtonBinding =
LayoutRoundButtonBinding.inflate(LayoutInflater.from(context), this, true)
private var mChecked = false
@@ -42,12 +41,8 @@ class RoundButton @JvmOverloads constructor(
private fun extractAttributes(attrs: AttributeSet?, defStyleAttr: Int) {
attrs?.let {
- val typedArray = context
- .obtainStyledAttributes(
- attrs,
- R.styleable.RoundButton,
- defStyleAttr,
- defStyleAttr
+ val typedArray = context.obtainStyledAttributes(
+ attrs, R.styleable.RoundButton, defStyleAttr, defStyleAttr
)
try {
@@ -55,6 +50,7 @@ class RoundButton @JvmOverloads constructor(
mChecked = typedArray.getBoolean(R.styleable.RoundButton_check_state, false)
tintColor = typedArray.getColor(R.styleable.RoundButton_tint_color, -1)
textColor = typedArray.getColor(R.styleable.RoundButton_text_color, -1)
+ isTextAllCaps = typedArray.getBoolean(R.styleable.RoundButton_text_all_caps, false)
isChecked = mChecked
} finally {
@@ -77,6 +73,7 @@ class RoundButton @JvmOverloads constructor(
private fun bindView() {
setTextAndVisibility(text, binding.sheetTextView)
setBackgroundTintColor(tintColor)
+ setTextCaps(isTextAllCaps)
}
private fun setTextAndVisibility(text: Int, textView: TextView) {
@@ -86,7 +83,7 @@ class RoundButton @JvmOverloads constructor(
}
}
- fun setBackgroundTintColor(tintColor: Int) {
+ private fun setBackgroundTintColor(tintColor: Int) {
if (tintColor != -1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
binding.sheetTextView.backgroundTintList = ColorStateList.valueOf(tintColor)
@@ -124,11 +121,15 @@ class RoundButton @JvmOverloads constructor(
private fun refreshLayoutState() {
super.refreshDrawableState()
- binding.sheetTextView.background = if (mChecked)
- ContextCompat.getDrawable(context, R.drawable.bg_information_button_selected)
- else
- ContextCompat.getDrawable(context, R.drawable.bg_information_button)
+ binding.sheetTextView.background = if (mChecked) ContextCompat.getDrawable(
+ context,
+ R.drawable.bg_information_button_selected
+ )
+ else ContextCompat.getDrawable(context, R.drawable.bg_information_button)
}
+ private fun setTextCaps(isTextAllCaps: Boolean) {
+ binding.sheetTextView.isAllCaps = isTextAllCaps
+ }
}
\ No newline at end of file
diff --git a/shared-ui/src/main/res/drawable/bg_dual_text_check.xml b/shared-ui/src/main/res/drawable/bg_dual_text_check.xml
new file mode 100644
index 000000000..9cca8653f
--- /dev/null
+++ b/shared-ui/src/main/res/drawable/bg_dual_text_check.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/shared-ui/src/main/res/drawable/device.xml b/shared-ui/src/main/res/drawable/device.xml
new file mode 100644
index 000000000..236bd69e3
--- /dev/null
+++ b/shared-ui/src/main/res/drawable/device.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
diff --git a/shared-ui/src/main/res/layout-hdpi/information_button.xml b/shared-ui/src/main/res/layout-hdpi/information_button.xml
index b4b9ef84f..f06c44ca4 100644
--- a/shared-ui/src/main/res/layout-hdpi/information_button.xml
+++ b/shared-ui/src/main/res/layout-hdpi/information_button.xml
@@ -1,11 +1,9 @@
+ android:layout_height="70dp">
+ android:layout_height="80dp">
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shared-ui/src/main/res/values/attrs.xml b/shared-ui/src/main/res/values/attrs.xml
index 7eec7c766..6cbaa3a85 100644
--- a/shared-ui/src/main/res/values/attrs.xml
+++ b/shared-ui/src/main/res/values/attrs.xml
@@ -14,11 +14,18 @@
+
+
+
+
+
+
+
diff --git a/shared-ui/src/main/res/values/styles.xml b/shared-ui/src/main/res/values/styles.xml
index f024c9024..71302242b 100644
--- a/shared-ui/src/main/res/values/styles.xml
+++ b/shared-ui/src/main/res/values/styles.xml
@@ -67,6 +67,10 @@
- 14sp
+
+
diff --git a/tella-keys/build.gradle b/tella-keys/build.gradle
index 0e52237c9..61c935303 100644
--- a/tella-keys/build.gradle
+++ b/tella-keys/build.gradle
@@ -37,6 +37,11 @@ dependencies {
api "androidx.core:core-ktx:$versions.ktx"
api "androidx.biometric:biometric:$versions.biometric"
+ //bouncycastle
+ api 'org.bouncycastle:bcprov-jdk18on:1.78'
+ api 'org.bouncycastle:bcpkix-jdk18on:1.78'
+
+
testImplementation "junit:junit:$versions.junit"
androidTestImplementation "androidx.test.ext:junit:$versions.testJunit"
androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espressoCore"
diff --git a/tella-keys/src/main/java/org/hzontal/tella/keys/key/LifecycleMainKey.java b/tella-keys/src/main/java/org/hzontal/tella/keys/key/LifecycleMainKey.java
index 8bc8db318..c771aae36 100644
--- a/tella-keys/src/main/java/org/hzontal/tella/keys/key/LifecycleMainKey.java
+++ b/tella-keys/src/main/java/org/hzontal/tella/keys/key/LifecycleMainKey.java
@@ -1,7 +1,5 @@
package org.hzontal.tella.keys.key;
-import android.content.Context;
-
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -11,8 +9,6 @@
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
-import org.hzontal.tella.keys.util.Preferences;
-
import timber.log.Timber;
/**
From 3302904259be775c133f9231810f6459b0233660 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Thu, 22 May 2025 22:04:08 +0100
Subject: [PATCH 003/153] show connect manual informations
---
.../tella/mobile/util/NavigationManager.kt | 5 ++++-
.../receipentflow/QRCodeFragment.kt | 20 +++++++++++++++++--
.../receipentflow/ShowDeviceInfoFragment.kt | 18 ++++++++++++++++-
.../fragment/vault/home/HomeVaultFragment.kt | 1 -
.../res/layout/show_device_info_layout.xml | 4 ++--
.../res/navigation/peer_to_peer_graph.xml | 16 +++++++++++----
6 files changed, 53 insertions(+), 11 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index 0c987252e..b3349874b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -2,7 +2,6 @@ package org.horizontal.tella.mobile.util
import android.os.Bundle
import org.horizontal.tella.mobile.R
-import org.horizontal.tella.mobile.domain.entity.uwazi.UwaziTemplate
import org.horizontal.tella.mobile.views.fragment.reports.di.NavControllerProvider
class NavigationManager(
@@ -182,4 +181,8 @@ class NavigationManager(
navigateToWithBundle(R.id.action_startNearBySharingFragment_to_scanQrCodeScreen)
}
+ fun navigateFromScanQrCodeToDeviceInfo() {
+ navigateToWithBundle(R.id.action_qrCodeScreen_to_deviceInfoScreen)
+ }
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 229783d68..a0efe6c9a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -23,6 +23,8 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
private val viewModel: PeerToPeerViewModel by activityViewModels()
private var server: TellaServer? = null
+ private var payload: PeerConnectionPayload? = null
+ private lateinit var qrPayload: String
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -32,6 +34,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
setupServerAndQr(ip)
}
handleBack()
+ handleConnectManually()
}
private fun setupServerAndQr(ip: String) {
@@ -50,14 +53,14 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val pin = "111111"
val port = port
- val payload = PeerConnectionPayload(
+ payload = PeerConnectionPayload(
connectCode = ip,
port = port,
certificateHash = certHash,
pin = pin
)
- val qrPayload = Gson().toJson(payload)
+ qrPayload = Gson().toJson(payload)
generateQrCode(qrPayload)
}
@@ -82,6 +85,19 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
binding.backBtn.setOnClickListener { nav().popBackStack() }
}
+ private fun handleConnectManually(){
+ binding.connectManuallyButton.setOnClickListener {
+ connectManually()
+ }
+ }
+
+ private fun connectManually() {
+ payload?.let {
+ bundle.putString("payload", qrPayload)
+ navManager().navigateFromScanQrCodeToDeviceInfo()
+ }
+ }
+
// TODO NEXT STEPS
//TODO WORK ON THE SENDER RESPONER
// TODO PREAPRE REGISTER RESPONE
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 698da492d..8f92adae6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -2,14 +2,30 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
+import com.google.gson.Gson
import org.horizontal.tella.mobile.databinding.ShowDeviceInfoLayoutBinding
+import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-class ShowDeviceInfoFragment : BaseBindingFragment(ShowDeviceInfoLayoutBinding::inflate) {
+class ShowDeviceInfoFragment :
+ BaseBindingFragment(ShowDeviceInfoLayoutBinding::inflate) {
+
+
+ private var payload: PeerConnectionPayload? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+ arguments?.getString("payload")?.let { payloadJson ->
+ payload = Gson().fromJson(payloadJson, PeerConnectionPayload::class.java)
+ }
initListeners()
+ initView()
+ }
+
+ private fun initView() {
+ binding.connectCode.setRightText(payload?.connectCode)
+ binding.pin.setRightText(payload?.pin)
+ binding.port.setRightText(payload?.port.toString())
}
private fun initListeners() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt
index 7e6d9e0e8..d7c26aac6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/home/HomeVaultFragment.kt
@@ -98,7 +98,6 @@ class HomeVaultFragment : BaseFragment(), VaultClickListener {
private var googleDriveServers: ArrayList? = null
private var dropBoxServers: ArrayList? = null
private var nextCloudServers: ArrayList? = null
- private var favoriteForms: ArrayList? = null
private lateinit var disposables: EventCompositeDisposable
private var reportServersCounted = false
private var collectServersCounted = false
diff --git a/mobile/src/main/res/layout/show_device_info_layout.xml b/mobile/src/main/res/layout/show_device_info_layout.xml
index f850f652d..dd1f8829b 100644
--- a/mobile/src/main/res/layout/show_device_info_layout.xml
+++ b/mobile/src/main/res/layout/show_device_info_layout.xml
@@ -87,7 +87,7 @@
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/connectCode"
- app:leftText="@string/connect_code" />
+ app:leftText="@string/pin" />
+ app:leftText="@string/port" />
+ tools:layout="@layout/connect_hotspot_layout">
+ tools:layout="@layout/scan_qrcode_fragment"/>
-
+ tools:layout="@layout/fragment_qr_code">
+
+
+
\ No newline at end of file
From bd15467a2934b590d17c9ef79a125eff13a3d592 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Fri, 23 May 2025 14:48:33 +0100
Subject: [PATCH 004/153] Finish sender manual connection design
---
mobile/src/main/AndroidManifest.xml | 8 +-
.../tella/mobile/util/NavigationManager.kt | 3 +
.../views/base_ui/BaseBindingFragment.kt | 1 -
.../receipentflow/ShowDeviceInfoFragment.kt | 1 -
.../senderflow/ScanQrCodeFragment.kt | 7 +
.../SenderManualConnectionFragment.kt | 70 ++++++++
.../res/layout/sender_manual_connection.xml | 163 ++++++++++++++++++
.../res/layout/show_device_info_layout.xml | 4 +-
.../res/navigation/peer_to_peer_graph.xml | 12 +-
mobile/src/main/res/values/strings.xml | 1 +
10 files changed, 260 insertions(+), 10 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
create mode 100644 mobile/src/main/res/layout/sender_manual_connection.xml
diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml
index 428d36e0d..37ad47641 100644
--- a/mobile/src/main/AndroidManifest.xml
+++ b/mobile/src/main/AndroidManifest.xml
@@ -662,10 +662,7 @@
android:name=".views.dialog.nextcloud.NextCloudLoginFlowActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar" />
-
+
@@ -704,7 +701,8 @@
+ android:theme="@style/AppTheme.NoActionBar"
+ android:windowSoftInputMode="adjustResize" />
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index b3349874b..698219654 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -185,4 +185,7 @@ class NavigationManager(
navigateToWithBundle(R.id.action_qrCodeScreen_to_deviceInfoScreen)
}
+ fun navigateFromScanQrCodeToSenderManualConnectionScreen() {
+ navigateToWithBundle(R.id.action_scanQrCodeScreen_to_senderManualConnectionScreen)
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseBindingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseBindingFragment.kt
index f5f0647bc..a8c39c889 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseBindingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseBindingFragment.kt
@@ -96,5 +96,4 @@ abstract class BaseBindingFragment(
_binding = null
isViewInitialized = false
}
-
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 8f92adae6..354b39ac7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -10,7 +10,6 @@ import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
class ShowDeviceInfoFragment :
BaseBindingFragment(ShowDeviceInfoLayoutBinding::inflate) {
-
private var payload: PeerConnectionPayload? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 64a36f774..82d6d66cb 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -46,6 +46,7 @@ class ScanQrCodeFragment :
}
}
handleBack()
+ initListeners()
}
private fun startScanning() {
@@ -108,4 +109,10 @@ class ScanQrCodeFragment :
binding.toolbar.backClickListener = { nav().popBackStack() }
binding.backBtn.setOnClickListener { nav().popBackStack() }
}
+
+ private fun initListeners() {
+ binding.connectManuallyButton.setOnClickListener {
+ navManager().navigateFromScanQrCodeToSenderManualConnectionScreen()
+ }
+ }
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
new file mode 100644
index 000000000..9a166d6ef
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -0,0 +1,70 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.activityViewModels
+import com.hzontal.tella_locking_ui.common.extensions.onChange
+import org.horizontal.tella.mobile.databinding.SenderManualConnectionBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.hzontal.shared_ui.bottomsheet.KeyboardUtil
+
+class SenderManualConnectionFragment :
+ BaseBindingFragment(SenderManualConnectionBinding::inflate) {
+
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initListeners()
+ initView()
+ }
+
+ private fun initView() {
+ binding.connectCode.onChange {
+ updateNextButtonState()
+ }
+ binding.port.onChange {
+ updateNextButtonState()
+ }
+
+ binding.port.onChange {
+ updateNextButtonState()
+ }
+
+ updateNextButtonState()
+
+ KeyboardUtil(binding.root)
+
+ }
+
+ private fun initListeners() {
+ binding.backBtn.setOnClickListener {
+ nav().popBackStack()
+ }
+
+ binding.nextBtn.setOnClickListener {
+
+ }
+ }
+
+ private fun isInputValid(): Boolean {
+ return binding.connectCode.text?.isNotBlank() == true &&
+ binding.pin.text?.isNotBlank() == true &&
+ binding.port.text?.isNotBlank() == true
+ }
+
+ private fun updateNextButtonState() {
+ val enabled = isInputValid()
+ binding.nextBtn.isEnabled = enabled
+ binding.nextBtn.setTextColor(
+ ContextCompat.getColor(
+ baseActivity,
+ if (enabled) android.R.color.white else android.R.color.darker_gray
+ )
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/sender_manual_connection.xml b/mobile/src/main/res/layout/sender_manual_connection.xml
new file mode 100644
index 000000000..2999a1ba4
--- /dev/null
+++ b/mobile/src/main/res/layout/sender_manual_connection.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/show_device_info_layout.xml b/mobile/src/main/res/layout/show_device_info_layout.xml
index dd1f8829b..f850f652d 100644
--- a/mobile/src/main/res/layout/show_device_info_layout.xml
+++ b/mobile/src/main/res/layout/show_device_info_layout.xml
@@ -87,7 +87,7 @@
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/connectCode"
- app:leftText="@string/pin" />
+ app:leftText="@string/connect_code" />
+ app:leftText="@string/connect_code" />
+ tools:layout="@layout/scan_qrcode_fragment">
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index fea695848..9265c460c 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1037,5 +1037,6 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Nearby sharing
How it works
https://tella-app.org/nearby-sharing/
+ Enter the recipient’s device\n information to find it on the network
From 2abd9ffbf36d86978a706398ebf9cfbb82ce4f2e Mon Sep 17 00:00:00 2001
From: wafa
Date: Fri, 23 May 2025 16:52:57 +0100
Subject: [PATCH 005/153] implement prepare upload view
---
.../tella/mobile/util/NavigationManager.kt | 3 +
.../peertopeer/PeerToPeerViewModel.kt | 10 +-
.../fragment/peertopeer/SenderViewModel.kt | 87 +++++++++
.../senderflow/PrepareUploadFragment.kt | 177 ++++++++++++++++++
.../senderflow/ScanQrCodeFragment.kt | 8 +-
.../res/layout/fragment_prepare_upload.xml | 118 ++++++++++++
.../res/navigation/peer_to_peer_graph.xml | 8 +
7 files changed, 406 insertions(+), 5 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
create mode 100644 mobile/src/main/res/layout/fragment_prepare_upload.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index 698219654..528ebe74e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -184,6 +184,9 @@ class NavigationManager(
fun navigateFromScanQrCodeToDeviceInfo() {
navigateToWithBundle(R.id.action_qrCodeScreen_to_deviceInfoScreen)
}
+ fun navigateFromScanQrCodeTo() {
+ navigateToWithBundle(R.id.action_scanQrCodeScreen_to_prepareUploadFragment)
+ }
fun navigateFromScanQrCodeToSenderManualConnectionScreen() {
navigateToWithBundle(R.id.action_scanQrCodeScreen_to_senderManualConnectionScreen)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 9faa3cb48..cfd8fa991 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -54,7 +54,8 @@ class PeerToPeerViewModel @Inject constructor(
private val _networkInfo = MutableLiveData()
val networkInfo: LiveData = _networkInfo
var currentNetworkInfo: NetworkInfo? = null
- private set
+ private val _registrationSuccess = MutableLiveData()
+ val registrationSuccess: LiveData get() = _registrationSuccess
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("MissingPermission", "DiscouragedPrivateApi")
@@ -172,11 +173,12 @@ class PeerToPeerViewModel @Inject constructor(
result.onSuccess {
Log.d("QRCode", "Registered successfully: $it")
val file = createFileFromAsset(context, "testDemo.txt")
- peerClient.prepareUpload(ip,port,hash,"test report",file,UUID.randomUUID().toString(),calculateSha256(file),UUID.randomUUID().toString())
- // update UI state
+ _registrationSuccess.postValue(true) // Notify success
}.onFailure {
+ // peerClient.prepareUpload(ip,port,hash,"test report",file,UUID.randomUUID().toString(),calculateSha256(file),UUID.randomUUID().toString())
+ // update UI state
Log.e("QRCode", "Registration failed: ${it.message}")
- // handle error (maybe post a value to LiveData)
+ _registrationSuccess.postValue(false) // Optional: Notify failure
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
new file mode 100644
index 000000000..2ab1cf6be
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -0,0 +1,87 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+import dagger.hilt.android.lifecycle.HiltViewModel
+import org.horizontal.tella.mobile.domain.entity.EntityStatus
+import org.horizontal.tella.mobile.domain.entity.Server
+import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
+import org.horizontal.tella.mobile.domain.entity.reports.ReportInstance
+import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BaseReportsViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class SenderViewModel @Inject constructor(
+
+) : BaseReportsViewModel() {
+ override fun clearDisposable() {
+ TODO("Not yet implemented")
+ }
+
+ override fun deleteReport(instance: ReportInstance) {
+ TODO("Not yet implemented")
+ }
+
+ override fun getReportBundle(instance: ReportInstance) {
+ TODO("Not yet implemented")
+ }
+
+ override fun getFormInstance(
+ title: String,
+ description: String,
+ files: List?,
+ server: Server,
+ id: Long?,
+ reportApiId: String,
+ status: EntityStatus
+ ): ReportInstance {
+ TODO("Not yet implemented")
+ }
+
+ override fun getDraftFormInstance(
+ title: String,
+ description: String,
+ files: List?,
+ server: Server,
+ id: Long?
+ ): ReportInstance {
+ TODO("Not yet implemented")
+ }
+
+ override fun listSubmitted() {
+ TODO("Not yet implemented")
+ }
+
+ override fun listOutbox() {
+ TODO("Not yet implemented")
+ }
+
+ override fun listDraftsOutboxAndSubmitted() {
+ TODO("Not yet implemented")
+ }
+
+ override fun listDrafts() {
+ TODO("Not yet implemented")
+ }
+
+ override fun saveSubmitted(reportInstance: ReportInstance) {
+ TODO("Not yet implemented")
+ }
+
+ override fun saveOutbox(reportInstance: ReportInstance) {
+ TODO("Not yet implemented")
+ }
+
+ override fun saveDraft(reportInstance: ReportInstance, exitAfterSave: Boolean) {
+ TODO("Not yet implemented")
+ }
+
+ override fun listServers() {
+ TODO("Not yet implemented")
+ }
+
+ override fun submitReport(instance: ReportInstance, backButtonPressed: Boolean) {
+ TODO("Not yet implemented")
+ }
+
+}
+
+
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
new file mode 100644
index 000000000..f995159fe
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -0,0 +1,177 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.setFragmentResultListener
+import androidx.recyclerview.widget.GridLayoutManager
+import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.hzontal.tella_vault.VaultFile
+import com.hzontal.tella_vault.filter.FilterType
+import dagger.hilt.android.AndroidEntryPoint
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.databinding.FragmentPrepareUploadBinding
+import org.horizontal.tella.mobile.media.MediaFileHandler
+import org.horizontal.tella.mobile.util.C
+import org.horizontal.tella.mobile.views.activity.camera.CameraActivity
+import org.horizontal.tella.mobile.views.activity.camera.CameraActivity.Companion.CAPTURE_WITH_AUTO_UPLOAD
+import org.horizontal.tella.mobile.views.adapters.reports.ReportsFilesRecyclerViewAdapter
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_AUDIO
+import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_VAULT_FILE
+import org.horizontal.tella.mobile.views.fragment.main_connexions.base.OnNavBckListener
+import org.horizontal.tella.mobile.views.fragment.recorder.REPORT_ENTRY
+import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.AttachmentsActivitySelector
+import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.VAULT_FILES_FILTER
+import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.VAULT_FILE_KEY
+import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.VAULT_PICKER_SINGLE
+import org.horizontal.tella.mobile.views.interfaces.IReportAttachmentsHandler
+import org.hzontal.shared_ui.bottomsheet.VaultSheetUtils.IVaultFilesSelector
+import org.hzontal.shared_ui.bottomsheet.VaultSheetUtils.showVaultSelectFilesSheet
+
+@AndroidEntryPoint
+class PrepareUploadFragment :
+ BaseBindingFragment(FragmentPrepareUploadBinding::inflate),
+ IReportAttachmentsHandler, OnNavBckListener {
+ private lateinit var gridLayoutManager: GridLayoutManager
+ private val filesRecyclerViewAdapter: ReportsFilesRecyclerViewAdapter by lazy {
+ ReportsFilesRecyclerViewAdapter(this)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setFragmentResultListener(BUNDLE_REPORT_AUDIO) { _, bundle ->
+ val file = bundle.get(BUNDLE_REPORT_VAULT_FILE) as VaultFile
+ bundle.remove(BUNDLE_REPORT_VAULT_FILE)
+ //putFiles(listOf(file))
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ initView()
+ initData()
+ }
+
+ private fun initView() {
+ gridLayoutManager = GridLayoutManager(context, 3)
+ binding.filesRecyclerView.apply {
+ layoutManager = gridLayoutManager
+ adapter = filesRecyclerViewAdapter
+ }
+ binding.toolbar.backClickListener = {
+ exitOrSave()
+ }
+
+ }
+
+ private fun exitOrSave() {
+
+ }
+
+ @SuppressLint("StringFormatInvalid")
+ private fun initData() {
+ }
+
+
+ private fun showSelectFilesSheet() {
+ showVaultSelectFilesSheet(baseActivity.supportFragmentManager,
+ baseActivity.getString(R.string.Uwazi_WidgetMedia_Take_Photo),
+ baseActivity.getString(R.string.Vault_RecordAudio_SheetAction),
+ baseActivity.getString(R.string.Uwazi_WidgetMedia_Select_From_Device),
+ baseActivity.getString(R.string.Uwazi_WidgetMedia_Select_From_Tella),
+ null,
+ baseActivity.getString(R.string.Uwazi_MiltiFileWidget_SelectFiles),
+ object : IVaultFilesSelector {
+ override fun importFromVault() {
+ showAttachmentsActivity()
+ }
+
+ override fun goToRecorder() {
+ showAudioRecorderActivity()
+ }
+
+ override fun goToCamera() {
+ showCameraActivity()
+ }
+
+ override fun importFromDevice() {
+ importMedia()
+ }
+ })
+ }
+
+
+ private fun showAttachmentsActivity() {
+ try {
+ baseActivity.startActivityForResult(
+ Intent(activity, AttachmentsActivitySelector::class.java)
+ // .putExtra(VAULT_FILE_KEY, Gson().toJson(ids))
+ .putExtra(
+ VAULT_FILES_FILTER, FilterType.ALL_WITHOUT_DIRECTORY
+ ).putExtra(VAULT_PICKER_SINGLE, false), C.MEDIA_FILE_ID
+ )
+ } catch (e: Exception) {
+ FirebaseCrashlytics.getInstance().recordException(e)
+ }
+ }
+
+ private fun showCameraActivity() {
+ try {
+ val intent = Intent(context, CameraActivity::class.java)
+ intent.apply {
+ putExtra(CameraActivity.INTENT_MODE, CameraActivity.IntentMode.COLLECT.name)
+ putExtra(CAPTURE_WITH_AUTO_UPLOAD, false)
+ }
+
+ baseActivity.startActivityForResult(intent, C.MEDIA_FILE_ID)
+ } catch (e: java.lang.Exception) {
+ FirebaseCrashlytics.getInstance().recordException(e)
+ }
+ }
+
+ private fun importMedia() {
+ baseActivity.maybeChangeTemporaryTimeout {
+ MediaFileHandler.startSelectMediaActivity(
+ activity, "image/* video/* audio/*",
+ arrayOf("image/*", "video/*", "audio/*"), C.IMPORT_FILE
+ )
+ }
+ }
+
+ private fun showAudioRecorderActivity() {
+ try {
+ bundle.putBoolean(REPORT_ENTRY, true)
+ this.navManager().navigateToMicro()
+ } catch (e: java.lang.Exception) {
+ FirebaseCrashlytics.getInstance().recordException(e)
+ }
+ }
+
+ @Deprecated("Deprecated in Java")
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (requestCode == C.MEDIA_FILE_ID && resultCode == Activity.RESULT_OK) {
+ val vaultFile = data?.getStringExtra(VAULT_FILE_KEY) ?: ""
+ // putFiles(viewModel.putVaultFilesInForm(vaultFile).blockingGet())
+ }
+ }
+
+
+ override fun playMedia(mediaFile: VaultFile?) {
+
+ }
+
+ override fun addFiles() {
+ showSelectFilesSheet()
+ }
+
+ override fun removeFiles() {
+ }
+
+ override fun onBackPressed(): Boolean {
+ exitOrSave()
+ return true
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 82d6d66cb..21d62795d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -33,7 +33,13 @@ class ScanQrCodeFragment :
barcodeView = CompoundBarcodeView(requireContext())
barcodeView = binding.qrCodeScanView
-
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ navManager().navigateFromScanQrCodeTo()
+ } else {
+ // handle error UI
+ }
+ }
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
diff --git a/mobile/src/main/res/layout/fragment_prepare_upload.xml b/mobile/src/main/res/layout/fragment_prepare_upload.xml
new file mode 100644
index 000000000..954845043
--- /dev/null
+++ b/mobile/src/main/res/layout/fragment_prepare_upload.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 81e74fb8d..25547ec83 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -36,6 +36,9 @@
android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow.ScanQrCodeFragment"
android:label="ScanQrCodeScreen"
tools:layout="@layout/scan_qrcode_fragment">
+
@@ -56,6 +59,11 @@
android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow.ShowDeviceInfoFragment"
android:label="DeviceInfoScreen"
tools:layout="@layout/show_device_info_layout" />
+
Date: Wed, 28 May 2025 18:21:25 +0100
Subject: [PATCH 006/153] implement add files in the send view
---
.../fragment/peertopeer/SenderViewModel.kt | 108 ++++++----------
.../peertopeer/activity/PeerToPeerActivity.kt | 12 +-
.../senderflow/PrepareUploadFragment.kt | 118 +++++++++++++++++-
.../senderflow/ScanQrCodeFragment.kt | 1 -
.../res/layout/fragment_prepare_upload.xml | 6 +-
5 files changed, 166 insertions(+), 79 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 2ab1cf6be..3028847c7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -1,87 +1,53 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer
+import androidx.lifecycle.ViewModel
+import com.hzontal.tella_vault.VaultFile
import dagger.hilt.android.lifecycle.HiltViewModel
+import io.reactivex.Observable
+import io.reactivex.Single
+import io.reactivex.schedulers.Schedulers
+import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.domain.entity.EntityStatus
import org.horizontal.tella.mobile.domain.entity.Server
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.entity.reports.ReportInstance
+import org.horizontal.tella.mobile.util.fromJsonToObjectList
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BaseReportsViewModel
import javax.inject.Inject
@HiltViewModel
class SenderViewModel @Inject constructor(
-
-) : BaseReportsViewModel() {
- override fun clearDisposable() {
- TODO("Not yet implemented")
- }
-
- override fun deleteReport(instance: ReportInstance) {
- TODO("Not yet implemented")
- }
-
- override fun getReportBundle(instance: ReportInstance) {
- TODO("Not yet implemented")
- }
-
- override fun getFormInstance(
- title: String,
- description: String,
- files: List?,
- server: Server,
- id: Long?,
- reportApiId: String,
- status: EntityStatus
- ): ReportInstance {
- TODO("Not yet implemented")
- }
-
- override fun getDraftFormInstance(
- title: String,
- description: String,
- files: List?,
- server: Server,
- id: Long?
- ): ReportInstance {
- TODO("Not yet implemented")
- }
-
- override fun listSubmitted() {
- TODO("Not yet implemented")
- }
-
- override fun listOutbox() {
- TODO("Not yet implemented")
- }
-
- override fun listDraftsOutboxAndSubmitted() {
- TODO("Not yet implemented")
- }
-
- override fun listDrafts() {
- TODO("Not yet implemented")
- }
-
- override fun saveSubmitted(reportInstance: ReportInstance) {
- TODO("Not yet implemented")
- }
-
- override fun saveOutbox(reportInstance: ReportInstance) {
- TODO("Not yet implemented")
+) : ViewModel() {
+
+ fun putVaultFilesInForm(vaultFileList: String): Single> {
+ return Single.fromCallable {
+ vaultFileList.fromJsonToObjectList(String::class.java) ?: emptyList()
+ }
+ .flatMap { fileIds ->
+ MyApplication.keyRxVault.rxVault
+ .firstOrError()
+ .flatMap { rxVault ->
+ Observable.fromIterable(fileIds)
+ .flatMapSingle { fileId ->
+ rxVault[fileId]
+ .subscribeOn(Schedulers.io())
+ .onErrorReturn { null } // safe, allows null
+ }
+ .filter { it != null } // filter out nulls
+ .map { it!! } // safe to force unwrap if you're sure it's not null now
+ .toList()
+ }
+ }
+ .subscribeOn(Schedulers.io())
+ }
+
+ fun mediaFilesToVaultFiles(files: List?): List {
+ val vaultFiles = ArrayList()
+ files?.map { mediaFile ->
+ vaultFiles.add(mediaFile.vaultFile)
+ }
+ return vaultFiles
}
-
- override fun saveDraft(reportInstance: ReportInstance, exitAfterSave: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun listServers() {
- TODO("Not yet implemented")
- }
-
- override fun submitReport(instance: ReportInstance, backButtonPressed: Boolean) {
- TODO("Not yet implemented")
- }
-
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
index c44c043b7..83c42259f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
@@ -1,10 +1,11 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer.activity
+import android.content.Intent
import android.os.Bundle
import org.horizontal.tella.mobile.databinding.ActivityPeerToPeerBinding
import org.horizontal.tella.mobile.views.base_ui.BaseLockActivity
-class PeerToPeerActivity : BaseLockActivity() {
+class PeerToPeerActivity : BaseLockActivity() {
private lateinit var binding: ActivityPeerToPeerBinding
override fun onCreate(savedInstanceState: Bundle?) {
@@ -12,4 +13,13 @@ class PeerToPeerActivity : BaseLockActivity() {
binding = ActivityPeerToPeerBinding.inflate(layoutInflater)
setContentView(binding.getRoot())
}
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ // Delegate onActivityResult to child fragments
+ supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
+ it.onActivityResult(requestCode, resultCode, data)
+ }
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index f995159fe..36eebb495 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -6,13 +6,16 @@ import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.setFragmentResultListener
+import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.hzontal.tella_locking_ui.common.extensions.onChange
import com.hzontal.tella_vault.VaultFile
import com.hzontal.tella_vault.filter.FilterType
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentPrepareUploadBinding
+import org.horizontal.tella.mobile.domain.entity.reports.ReportInstance
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.C
import org.horizontal.tella.mobile.views.activity.camera.CameraActivity
@@ -20,8 +23,10 @@ import org.horizontal.tella.mobile.views.activity.camera.CameraActivity.Companio
import org.horizontal.tella.mobile.views.adapters.reports.ReportsFilesRecyclerViewAdapter
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_AUDIO
+import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_FORM_INSTANCE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_VAULT_FILE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.OnNavBckListener
+import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
import org.horizontal.tella.mobile.views.fragment.recorder.REPORT_ENTRY
import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.AttachmentsActivitySelector
import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.VAULT_FILES_FILTER
@@ -30,12 +35,18 @@ import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.VAULT_PICKER
import org.horizontal.tella.mobile.views.interfaces.IReportAttachmentsHandler
import org.hzontal.shared_ui.bottomsheet.VaultSheetUtils.IVaultFilesSelector
import org.hzontal.shared_ui.bottomsheet.VaultSheetUtils.showVaultSelectFilesSheet
+import org.hzontal.shared_ui.utils.DialogUtils
@AndroidEntryPoint
class PrepareUploadFragment :
BaseBindingFragment(FragmentPrepareUploadBinding::inflate),
IReportAttachmentsHandler, OnNavBckListener {
private lateinit var gridLayoutManager: GridLayoutManager
+ private var isTitleEnabled = false
+ private var reportInstance: ReportInstance? = null
+ private val viewModel: SenderViewModel by viewModels()
+ private var isNewDraft = true
+
private val filesRecyclerViewAdapter: ReportsFilesRecyclerViewAdapter by lazy {
ReportsFilesRecyclerViewAdapter(this)
}
@@ -45,7 +56,7 @@ class PrepareUploadFragment :
setFragmentResultListener(BUNDLE_REPORT_AUDIO) { _, bundle ->
val file = bundle.get(BUNDLE_REPORT_VAULT_FILE) as VaultFile
bundle.remove(BUNDLE_REPORT_VAULT_FILE)
- //putFiles(listOf(file))
+ putFiles(listOf(file))
}
}
@@ -64,6 +75,48 @@ class PrepareUploadFragment :
exitOrSave()
}
+ arguments?.let { bundle ->
+ if (bundle.get(BUNDLE_REPORT_FORM_INSTANCE) != null) {
+ reportInstance = bundle.get(BUNDLE_REPORT_FORM_INSTANCE) as ReportInstance
+ bundle.remove(BUNDLE_REPORT_FORM_INSTANCE)
+ }
+ }
+
+ reportInstance?.let { instance ->
+ binding.reportTitleEt.setText(instance.title)
+ putFiles(viewModel.mediaFilesToVaultFiles(instance.widgetMediaFiles))
+ isNewDraft = false
+ }
+ highLightButtonsInit()
+ checkIsNewDraftEntry()
+ }
+
+ private fun checkIsNewDraftEntry() {
+ if (isNewDraft) {
+ // binding.deleteBtn.invisible()
+ // binding.sendLaterBtn.show()
+ binding.sendReportBtn.text = getString(R.string.collect_end_action_submit)
+ } else {
+ // binding.deleteBtn.show()
+ // binding.sendLaterBtn.invisible()
+ binding.sendReportBtn.text = getString(R.string.Send_Action_Label)
+ }
+ }
+
+
+ private fun highLightButtonsInit() {
+ binding.apply {
+ reportTitleEt.let { title ->
+ isTitleEnabled = title.length() > 0
+ }
+
+ reportTitleEt.onChange { title ->
+ isTitleEnabled = title.isNotEmpty()
+ highLightButtons()
+ }
+
+ }
+
}
private fun exitOrSave() {
@@ -72,7 +125,9 @@ class PrepareUploadFragment :
@SuppressLint("StringFormatInvalid")
private fun initData() {
- }
+
+
+ }
private fun showSelectFilesSheet() {
@@ -153,10 +208,67 @@ class PrepareUploadFragment :
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == C.MEDIA_FILE_ID && resultCode == Activity.RESULT_OK) {
val vaultFile = data?.getStringExtra(VAULT_FILE_KEY) ?: ""
- // putFiles(viewModel.putVaultFilesInForm(vaultFile).blockingGet())
+ putFiles(viewModel.putVaultFilesInForm(vaultFile).blockingGet())
}
}
+ private fun putFiles(vaultFileList: List) {
+ val filteredFiles = vaultFileList.filter { file ->
+ isValidFile(file)
+ }.also {
+ if (it.size != vaultFileList.size) {
+ showToast(getString(R.string.nextcloud_file_size_limit))
+ }
+ }
+
+ // Insert the filtered files
+ filteredFiles.forEach { file ->
+ filesRecyclerViewAdapter.insertAttachment(file)
+ }
+
+ // Ensure visibility and highlight buttons
+ binding.filesRecyclerView.visibility = View.VISIBLE
+ highLightButtons()
+ }
+
+
+ private fun highLightButtons() {
+ val isSubmitEnabled =
+ isTitleEnabled && filesRecyclerViewAdapter.getFiles()
+ .isNotEmpty()
+
+ val disabled: Float = context?.getString(R.string.alpha_disabled)?.toFloat() ?: 1.0f
+ val enabled: Float = context?.getString(R.string.alpha_enabled)?.toFloat() ?: 1.0f
+
+ binding.sendReportBtn.setBackgroundResource(if (isSubmitEnabled) R.drawable.bg_round_orange_btn else R.drawable.bg_round_orange16_btn)
+ binding.sendReportBtn.alpha = (if (isSubmitEnabled) enabled else disabled)
+
+ initClickListeners(isSubmitEnabled)
+ }
+
+ private fun initClickListeners(isSubmitEnabled: Boolean) {
+ binding.sendReportBtn.setOnClickListener {
+ if (isSubmitEnabled) {
+ } else {
+ showSubmitReportErrorSnackBar()
+ }
+ }
+ }
+ private fun showSubmitReportErrorSnackBar() {
+ val errorRes = R.string.Snackbar_Submit_Report_WithProject_Error
+
+ DialogUtils.showBottomMessage(
+ baseActivity,
+ getString(errorRes),
+ false
+ )
+ }
+
+ // Helper function to check if the file is valid (less than or equal to 20MB)
+ private fun isValidFile(file: VaultFile): Boolean {
+ val isFileSizeValid = file.size <= 20 * 1024 * 1024 // 20MB in bytes
+ return isFileSizeValid
+ }
override fun playMedia(mediaFile: VaultFile?) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 21d62795d..27938c6dc 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -79,7 +79,6 @@ class ScanQrCodeFragment :
}
}
-
override fun possibleResultPoints(resultPoints: MutableList?) {
}
})
diff --git a/mobile/src/main/res/layout/fragment_prepare_upload.xml b/mobile/src/main/res/layout/fragment_prepare_upload.xml
index 954845043..7c01fd7e9 100644
--- a/mobile/src/main/res/layout/fragment_prepare_upload.xml
+++ b/mobile/src/main/res/layout/fragment_prepare_upload.xml
@@ -45,9 +45,9 @@
android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
android:layout_marginTop="16dp"
android:textColorHint="@color/wa_white"
+ app:errorTextAppearance="@style/TextEntryLayoutErrorStyle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:errorTextAppearance="@style/TextEntryLayoutErrorStyle"
app:layout_constraintTop_toBottomOf="@id/toolbar">
+ app:backgroundTint="@color/wa_white"
+ app:errorTextAppearance="@style/TextEntryLayoutErrorStyle" />
Date: Thu, 29 May 2025 14:37:45 +0100
Subject: [PATCH 007/153] continue on implementing the design of the send view
---
.../mobile/views/fragment/peertopeer/SenderViewModel.kt | 4 ----
.../peertopeer/senderflow/PrepareUploadFragment.kt | 9 ++++-----
mobile/src/main/res/layout/fragment_prepare_upload.xml | 3 ++-
mobile/src/main/res/values/strings.xml | 5 ++---
4 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 3028847c7..fda0c2d2a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -7,12 +7,8 @@ import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import org.horizontal.tella.mobile.MyApplication
-import org.horizontal.tella.mobile.domain.entity.EntityStatus
-import org.horizontal.tella.mobile.domain.entity.Server
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
-import org.horizontal.tella.mobile.domain.entity.reports.ReportInstance
import org.horizontal.tella.mobile.util.fromJsonToObjectList
-import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BaseReportsViewModel
import javax.inject.Inject
@HiltViewModel
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 36eebb495..5f42b8d23 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -231,6 +231,9 @@ class PrepareUploadFragment :
highLightButtons()
}
+ override fun removeFiles() {
+ highLightButtons()
+ }
private fun highLightButtons() {
val isSubmitEnabled =
@@ -255,7 +258,7 @@ class PrepareUploadFragment :
}
}
private fun showSubmitReportErrorSnackBar() {
- val errorRes = R.string.Snackbar_Submit_Report_WithProject_Error
+ val errorRes = R.string.Snackbar_Submit_Files_Error
DialogUtils.showBottomMessage(
baseActivity,
@@ -271,16 +274,12 @@ class PrepareUploadFragment :
}
override fun playMedia(mediaFile: VaultFile?) {
-
}
override fun addFiles() {
showSelectFilesSheet()
}
- override fun removeFiles() {
- }
-
override fun onBackPressed(): Boolean {
exitOrSave()
return true
diff --git a/mobile/src/main/res/layout/fragment_prepare_upload.xml b/mobile/src/main/res/layout/fragment_prepare_upload.xml
index 7c01fd7e9..a6d6ba9b3 100644
--- a/mobile/src/main/res/layout/fragment_prepare_upload.xml
+++ b/mobile/src/main/res/layout/fragment_prepare_upload.xml
@@ -61,6 +61,7 @@
android:textColor="@color/wa_white"
app:backgroundTint="@color/wa_white"
app:errorTextAppearance="@style/TextEntryLayoutErrorStyle" />
+
Unsaved changes
Your changes have not been saved. Would you like to save before exiting?
EXIT WITHOUT SAVING
- Incorrect Pattern.
-
-
+ Incorrect Pattern
+ To submit a report, please type in a title and attach a file.
Incorrect Pin.
From b8252f2c9c4805a71b5c52fbfb90839c0e98a5c8 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Thu, 29 May 2025 20:28:08 +0100
Subject: [PATCH 008/153] WIP manual connection
---
.../data/peertopeer/FingerprintFetcher.kt | 45 +++++++
.../data/peertopeer/TellaPeerToPeerClient.kt | 19 +++
.../peertopeer/PeerToPeerViewModel.kt | 50 ++++----
.../receipentflow/ConnectHotspotFragment.kt | 1 -
.../ConnectManuallyVerificationFragment.kt | 31 +++++
.../receipentflow/VerificationInfoFragment.kt | 4 -
.../SenderManualConnectionFragment.kt | 3 +
.../layout/connect_manually_verification.xml | 120 ++++++++++++++++++
.../res/layout/sender_manual_connection.xml | 3 +-
.../res/layout/show_device_info_layout.xml | 5 +-
.../res/navigation/peer_to_peer_graph.xml | 13 +-
mobile/src/main/res/values/strings.xml | 4 +-
12 files changed, 262 insertions(+), 36 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectManuallyVerificationFragment.kt
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt
create mode 100644 mobile/src/main/res/layout/connect_manually_verification.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt
new file mode 100644
index 000000000..d36c87530
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt
@@ -0,0 +1,45 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.horizontal.tella.mobile.certificate.CertificateUtils
+import java.net.SocketTimeoutException
+import java.security.SecureRandom
+import java.security.cert.X509Certificate
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+
+object FingerprintFetcher {
+
+ suspend fun fetch(ip: String, port: Int): Result = withContext(Dispatchers.IO) {
+ return@withContext try {
+ val socket = createUnsafeSSLSocket(ip, port)
+ val cert = socket.session.peerCertificates[0] as X509Certificate
+ val fingerprint = CertificateUtils.getPublicKeyHash(cert)
+ socket.close()
+ Result.success(fingerprint)
+ } catch (e: SocketTimeoutException) {
+ Result.failure(RuntimeException("Connection timed out", e))
+ } catch (e: Exception) {
+ Result.failure(e)
+ }
+ }
+
+ private fun createUnsafeSSLSocket(ip: String, port: Int): SSLSocket {
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(null, arrayOf(TrustAllCerts()), SecureRandom())
+ val factory = sslContext.socketFactory as SSLSocketFactory
+ val socket = factory.createSocket(ip, port) as SSLSocket
+ socket.soTimeout = 5000
+ socket.startHandshake()
+ return socket
+ }
+
+ private class TrustAllCerts : X509TrustManager {
+ override fun checkClientTrusted(chain: Array, authType: String) {}
+ override fun checkServerTrusted(chain: Array, authType: String) {}
+ override fun getAcceptedIssuers(): Array = arrayOf()
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 6345097b1..01075581b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -19,6 +19,8 @@ import java.security.cert.X509Certificate
import java.util.UUID
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
@@ -180,4 +182,21 @@ class TellaPeerToPeerClient {
}
}
+ suspend fun fetchServerFingerprint(ip: String, port: Int): Result = withContext(Dispatchers.IO) {
+ try {
+ val socket = SSLSocketFactory.getDefault()
+ .createSocket(ip, port) as SSLSocket
+ socket.soTimeout = 5000
+ socket.startHandshake()
+
+ val cert = socket.session.peerCertificates[0] as X509Certificate
+ val fingerprint = CertificateUtils.getPublicKeyHash(cert)
+ Result.success(fingerprint)
+ } catch (e: Exception) {
+ Result.failure(e)
+ }
+ }
+
+
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index cfd8fa991..7f3318380 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -17,39 +17,25 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import okhttp3.MediaType.Companion.toMediaType
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.RequestBody.Companion.toRequestBody
-import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.NetworkInfo
-import org.json.JSONArray
-import org.json.JSONObject
+import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.net.Inet4Address
import java.net.NetworkInterface
import java.security.MessageDigest
-import java.security.SecureRandom
-import java.security.cert.CertificateException
-import java.security.cert.X509Certificate
import java.util.UUID
-import java.util.concurrent.TimeUnit
import javax.inject.Inject
-import javax.net.ssl.SSLContext
-import javax.net.ssl.TrustManager
-import javax.net.ssl.X509TrustManager
@HiltViewModel
class PeerToPeerViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val peerClient: TellaPeerToPeerClient
-) :
- ViewModel() {
+) : ViewModel() {
private val _networkInfo = MutableLiveData()
val networkInfo: LiveData = _networkInfo
@@ -145,7 +131,6 @@ class PeerToPeerViewModel @Inject constructor(
}
}
- @SuppressLint("DiscouragedPrivateApi")
private fun getDeviceHotspotIpAddress(): String? {
return try {
val networkInterfaces = NetworkInterface.getNetworkInterfaces()
@@ -173,9 +158,16 @@ class PeerToPeerViewModel @Inject constructor(
result.onSuccess {
Log.d("QRCode", "Registered successfully: $it")
val file = createFileFromAsset(context, "testDemo.txt")
- _registrationSuccess.postValue(true) // Notify success
- }.onFailure {
- // peerClient.prepareUpload(ip,port,hash,"test report",file,UUID.randomUUID().toString(),calculateSha256(file),UUID.randomUUID().toString())
+ peerClient.prepareUpload(
+ ip,
+ port,
+ hash,
+ "test report",
+ file,
+ UUID.randomUUID().toString(),
+ calculateSha256(file),
+ UUID.randomUUID().toString()
+ )
// update UI state
Log.e("QRCode", "Registration failed: ${it.message}")
_registrationSuccess.postValue(false) // Optional: Notify failure
@@ -183,6 +175,19 @@ class PeerToPeerViewModel @Inject constructor(
}
}
+ fun handleCertificate(ip: String, port: String, pin: String) {
+ viewModelScope.launch {
+ val result = FingerprintFetcher.fetch(ip, port.toInt())
+
+ result.onSuccess { hash ->
+ Timber.d("hash ***** $hash")
+ }.onFailure { error ->
+ Timber.d("error ***** $error")
+ }
+
+ }
+ }
+
private fun createFileFromAsset(context: Context, assetFileName: String): File {
// Create a temporary file in the cache directory
@@ -203,8 +208,6 @@ class PeerToPeerViewModel @Inject constructor(
return tempFile
}
-
-
private fun calculateSha256(file: File): String {
val digest = MessageDigest.getInstance("SHA-256")
file.inputStream().use { input ->
@@ -218,5 +221,4 @@ class PeerToPeerViewModel @Inject constructor(
}
-
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index ecd84c81c..b2f5e9ed2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -30,7 +30,6 @@ class ConnectHotspotFragment :
}
private fun initObservers() {
-
viewModel.networkInfo.observe(viewLifecycleOwner) { info ->
when (info.type) {
ConnectionType.HOTSPOT, ConnectionType.WIFI, ConnectionType.CELLULAR -> {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectManuallyVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectManuallyVerificationFragment.kt
new file mode 100644
index 000000000..e0499bcee
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectManuallyVerificationFragment.kt
@@ -0,0 +1,31 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+import android.os.Bundle
+import android.view.View
+import com.google.gson.Gson
+import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
+import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+
+class ConnectManuallyVerificationFragment:
+ BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
+
+ private var payload: PeerConnectionPayload? = null
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ arguments?.getString("payload")?.let { payloadJson ->
+ payload = Gson().fromJson(payloadJson, PeerConnectionPayload::class.java)
+ }
+ initListeners()
+ initView()
+ }
+
+ private fun initView() {
+
+ }
+
+ private fun initListeners() {
+
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt
deleted file mode 100644
index 5af7e3916..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/VerificationInfoFragment.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
-
-class VerificationInfoFragment {
-}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index 9a166d6ef..4facedaa7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -65,6 +65,9 @@ class SenderManualConnectionFragment :
if (enabled) android.R.color.white else android.R.color.darker_gray
)
)
+ binding.nextBtn.setOnClickListener {
+ viewModel.handleCertificate(ip = binding.connectCode.text.toString(), port = binding.port.text.toString(), pin = binding.pin.text.toString())
+ }
}
}
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/connect_manually_verification.xml b/mobile/src/main/res/layout/connect_manually_verification.xml
new file mode 100644
index 000000000..d9a60761f
--- /dev/null
+++ b/mobile/src/main/res/layout/connect_manually_verification.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/src/main/res/layout/sender_manual_connection.xml b/mobile/src/main/res/layout/sender_manual_connection.xml
index 2999a1ba4..7b1c0e8ba 100644
--- a/mobile/src/main/res/layout/sender_manual_connection.xml
+++ b/mobile/src/main/res/layout/sender_manual_connection.xml
@@ -74,7 +74,8 @@
android:hint="@string/connect_code"
android:imeOptions="actionNext"
android:importantForAutofill="no"
- android:inputType="number"
+ android:inputType="textNoSuggestions"
+ android:digits="0123456789."
android:maxLines="1"
android:textColor="@color/wa_white"
android:textDirection="ltr"
diff --git a/mobile/src/main/res/layout/show_device_info_layout.xml b/mobile/src/main/res/layout/show_device_info_layout.xml
index f850f652d..3cc3442e0 100644
--- a/mobile/src/main/res/layout/show_device_info_layout.xml
+++ b/mobile/src/main/res/layout/show_device_info_layout.xml
@@ -1,7 +1,6 @@
@@ -87,7 +86,7 @@
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/connectCode"
- app:leftText="@string/connect_code" />
+ app:leftText="@string/pin" />
+ app:leftText="@string/port" />
+
+
+ tools:layout="@layout/sender_manual_connection" >
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index d333fb2ca..7dfb7e7fc 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1017,7 +1017,6 @@ Would you like to share analytics with the Tella team?
Make sure that this sequence matches what is shown on the sender’s device.
If the sequence on your device does not match the sequence on the sender’s device, the connection may not be secure and should be discarded.
Confirm and connect
- Discard and start over
Wi-Fi
Get connected
Make sure both devices are connected to the same Wi-Fi network
@@ -1037,5 +1036,6 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
How it works
https://tella-app.org/nearby-sharing/
Enter the recipient’s device\n information to find it on the network
-
+ Make sure that this sequence matches what is shown on the sender’s device.
+ Discard and start over
From 49423e0155884fcb374ce6e7185d01353bcb2b07 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Fri, 30 May 2025 13:03:29 +0100
Subject: [PATCH 009/153] WIP show hash flow
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 4 ---
.../peertopeer/PeerToPeerViewModel.kt | 9 ++++-
...nt.kt => RecipientVerificationFragment.kt} | 2 +-
.../SenderManualConnectionFragment.kt | 16 ++++++++-
.../senderflow/SenderVerificationFragment.kt | 33 +++++++++++++++++++
.../layout/connect_manually_verification.xml | 2 +-
.../res/navigation/peer_to_peer_graph.xml | 22 ++++++++++---
mobile/src/main/res/values/strings.xml | 2 ++
8 files changed, 77 insertions(+), 13 deletions(-)
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/{ConnectManuallyVerificationFragment.kt => RecipientVerificationFragment.kt} (95%)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 3a56cb036..edb47fe4e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -14,13 +14,10 @@ import io.ktor.server.engine.sslConnector
import io.ktor.server.netty.Netty
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.request.receive
-import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
-import kotlinx.serialization.json.buildJsonObject
-import kotlinx.serialization.json.put
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
@@ -31,7 +28,6 @@ import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.util.UUID
-import kotlin.reflect.jvm.internal.impl.load.kotlin.JvmType
const val port = 53317
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 7f3318380..dcac2de85 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -30,6 +30,7 @@ import java.net.NetworkInterface
import java.security.MessageDigest
import java.util.UUID
import javax.inject.Inject
+import kotlin.jvm.Throws
@HiltViewModel
class PeerToPeerViewModel @Inject constructor(
@@ -42,6 +43,10 @@ class PeerToPeerViewModel @Inject constructor(
var currentNetworkInfo: NetworkInfo? = null
private val _registrationSuccess = MutableLiveData()
val registrationSuccess: LiveData get() = _registrationSuccess
+ private val _getHashSuccess = MutableLiveData()
+ val getHashSuccess: LiveData get() = _getHashSuccess
+ private val _getHashError = MutableLiveData()
+ val getHashError: LiveData get() = _getHashError
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("MissingPermission", "DiscouragedPrivateApi")
@@ -169,7 +174,7 @@ class PeerToPeerViewModel @Inject constructor(
UUID.randomUUID().toString()
)
// update UI state
- Log.e("QRCode", "Registration failed: ${it.message}")
+ // Log.e("QRCode", "Registration failed: ${it.message}")
_registrationSuccess.postValue(false) // Optional: Notify failure
}
}
@@ -180,8 +185,10 @@ class PeerToPeerViewModel @Inject constructor(
val result = FingerprintFetcher.fetch(ip, port.toInt())
result.onSuccess { hash ->
+ _getHashSuccess.postValue(hash)
Timber.d("hash ***** $hash")
}.onFailure { error ->
+ _getHashError.postValue(error)
Timber.d("error ***** $error")
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectManuallyVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
similarity index 95%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectManuallyVerificationFragment.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index e0499bcee..9537fb46b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectManuallyVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -7,7 +7,7 @@ import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBindin
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-class ConnectManuallyVerificationFragment:
+class RecipientVerificationFragment:
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
private var payload: PeerConnectionPayload? = null
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index 4facedaa7..75f5e3e22 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -66,7 +66,21 @@ class SenderManualConnectionFragment :
)
)
binding.nextBtn.setOnClickListener {
- viewModel.handleCertificate(ip = binding.connectCode.text.toString(), port = binding.port.text.toString(), pin = binding.pin.text.toString())
+ viewModel.handleCertificate(
+ ip = binding.connectCode.text.toString(),
+ port = binding.port.text.toString(),
+ pin = binding.pin.text.toString()
+ )
+ }
+ }
+
+ private fun initObservers() {
+ viewModel.getHashSuccess.observe(viewLifecycleOwner) { hash ->
+
+ }
+
+ viewModel.getHashError.observe(viewLifecycleOwner) { error->
+ error.localizedMessage?.let { showToast(it) }
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
new file mode 100644
index 000000000..9c322db74
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -0,0 +1,33 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
+
+import android.os.Bundle
+import android.view.View
+import com.google.gson.Gson
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
+import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+
+class SenderVerificationFragment :
+ BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
+
+ private var payload: PeerConnectionPayload? = null
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ arguments?.getString("payload")?.let { payloadJson ->
+ payload = Gson().fromJson(payloadJson, PeerConnectionPayload::class.java)
+ }
+ initListeners()
+ initView()
+ }
+
+ private fun initView() {
+ binding.titleDescTextView.text = getString(R.string.make_sure_sequence_matches_recipient)
+ binding.warningTextView.text = getString(R.string.sequence_mismatch_warning_recipient)
+ }
+
+ private fun initListeners() {
+
+ }
+}
diff --git a/mobile/src/main/res/layout/connect_manually_verification.xml b/mobile/src/main/res/layout/connect_manually_verification.xml
index d9a60761f..022c99308 100644
--- a/mobile/src/main/res/layout/connect_manually_verification.xml
+++ b/mobile/src/main/res/layout/connect_manually_verification.xml
@@ -81,7 +81,7 @@
android:layout_marginTop="@dimen/activity_horizontal_large_margin"
android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
android:gravity="start"
- android:text="@string/make_sure_sequence_matches"
+ android:text="@string/sequence_mismatch_warning"
android:textColor="@android:color/white"
app:layout_constraintTop_toBottomOf="@id/hashContentTextView"
app:layout_constraintBottom_toTopOf="@+id/confirmAndConnectBtn"
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 7b68c48ec..046e4ed78 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -33,7 +33,7 @@
@@ -64,18 +64,30 @@
android:id="@+id/deviceInfoScreen"
android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow.ShowDeviceInfoFragment"
android:label="DeviceInfoScreen"
- tools:layout="@layout/show_device_info_layout" />
+ tools:layout="@layout/show_device_info_layout" >
+
+
+
+
+
+
+ android:label="PrepareUploadFragment"
+ tools:layout="@layout/fragment_prepare_upload" />
+ tools:layout="@layout/sender_manual_connection">
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index 7dfb7e7fc..e98c87573 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1037,5 +1037,7 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
https://tella-app.org/nearby-sharing/
Enter the recipient’s device\n information to find it on the network
Make sure that this sequence matches what is shown on the sender’s device.
+ Make sure that this sequence matches what is shown on the recipient’s device.
+ If the sequence on your device does not match the sequence on the recipient’s device, the connection may not be secure and should be discarded.
Discard and start over
From ec8494314ef658da244b55bfe923f3edb8d43c5f Mon Sep 17 00:00:00 2001
From: wafa
Date: Mon, 2 Jun 2025 14:12:03 +0100
Subject: [PATCH 010/153] wip prepareUpload api implementation
---
.../fragment/peertopeer/PeerSessionManager.kt | 26 ++++++++++
.../peertopeer/PeerToPeerViewModel.kt | 23 +++-----
.../fragment/peertopeer/SenderViewModel.kt | 52 +++++++++++++++++++
.../senderflow/PrepareUploadFragment.kt | 30 +++++++++--
4 files changed, 112 insertions(+), 19 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
new file mode 100644
index 000000000..e28cfb07a
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
@@ -0,0 +1,26 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+/**
+ * Created by wafa on 2/6/2025.
+ */
+
+object PeerSessionManager {
+ var ip: String? = null
+ var port: String? = null
+ var hash: String? = null
+ var sessionId: String? = null
+
+ fun isSessionValid(): Boolean {
+ return !ip.isNullOrEmpty() &&
+ !port.isNullOrEmpty() &&
+ !hash.isNullOrEmpty() &&
+ !sessionId.isNullOrEmpty()
+ }
+
+ fun clear() {
+ ip = null
+ port = null
+ hash = null
+ sessionId = null
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index dcac2de85..10ac430d0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -160,23 +160,14 @@ class PeerToPeerViewModel @Inject constructor(
fun onQrCodeParsed(ip: String, port: String, hash: String, pin: String) {
viewModelScope.launch {
val result = peerClient.registerPeerDevice(ip, port, hash, pin)
- result.onSuccess {
- Log.d("QRCode", "Registered successfully: $it")
- val file = createFileFromAsset(context, "testDemo.txt")
- peerClient.prepareUpload(
- ip,
- port,
- hash,
- "test report",
- file,
- UUID.randomUUID().toString(),
- calculateSha256(file),
- UUID.randomUUID().toString()
- )
+ result.onSuccess { sessionId ->
+ Log.d("QRCode", "Registered successfully: $sessionId")
+ PeerSessionManager.ip = ip
+ PeerSessionManager.port = port
+ PeerSessionManager.hash = hash
+ PeerSessionManager.sessionId = sessionId
// update UI state
- // Log.e("QRCode", "Registration failed: ${it.message}")
- _registrationSuccess.postValue(false) // Optional: Notify failure
- }
+ _registrationSuccess.postValue(true)
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index fda0c2d2a..b6721ed77 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -1,19 +1,33 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer
+import android.content.Context
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
import com.hzontal.tella_vault.VaultFile
import dagger.hilt.android.lifecycle.HiltViewModel
+import dagger.hilt.android.qualifiers.ApplicationContext
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.MyApplication
+import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
+import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.util.fromJsonToObjectList
+import timber.log.Timber
+import java.io.File
import javax.inject.Inject
+
@HiltViewModel
class SenderViewModel @Inject constructor(
+ private val peerClient: TellaPeerToPeerClient
) : ViewModel() {
+ private val _prepareResults = MutableLiveData>()
+ val prepareResults: LiveData> = _prepareResults
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
@@ -44,6 +58,44 @@ class SenderViewModel @Inject constructor(
}
return vaultFiles
}
+
+ fun prepareUploadsFromVaultFiles(
+ files: List,
+ ip: String,
+ port: String,
+ expectedFingerprint: String,
+ sessionId: String,
+ title: String = "Title of the report"
+ ) {
+ viewModelScope.launch {
+ val successfulResponses = mutableListOf()
+
+ for (file in files) {
+ val result = peerClient.prepareUpload(
+ ip = ip,
+ port = port,
+ expectedFingerprint = expectedFingerprint,
+ title = title,
+ file = File(file.path),
+ fileId = file.id,
+ sha256 = file.hash,
+ sessionId = sessionId
+ )
+
+ result.onSuccess { transmissionId ->
+ Timber.d("Success: transmissionId = $transmissionId")
+ successfulResponses.add(PeerPrepareUploadResponse(transmissionId))
+ }.onFailure {
+ Timber.e(it, "Failed to prepare upload")
+ // You can log or ignore errors here — not returned to LiveData
+ }
+ }
+
+ _prepareResults.postValue(successfulResponses)
+ }
+ }
+
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 5f42b8d23..d7f29e516 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -14,6 +14,7 @@ import com.hzontal.tella_vault.VaultFile
import com.hzontal.tella_vault.filter.FilterType
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.databinding.FragmentPrepareUploadBinding
import org.horizontal.tella.mobile.domain.entity.reports.ReportInstance
import org.horizontal.tella.mobile.media.MediaFileHandler
@@ -87,6 +88,13 @@ class PrepareUploadFragment :
putFiles(viewModel.mediaFilesToVaultFiles(instance.widgetMediaFiles))
isNewDraft = false
}
+
+ viewModel.prepareResults.observe(viewLifecycleOwner) { responses ->
+ responses.forEach { response ->
+ val id = response.transmissionId
+ // navigate to next screen
+ }
+ }
highLightButtonsInit()
checkIsNewDraftEntry()
}
@@ -104,6 +112,7 @@ class PrepareUploadFragment :
}
+
private fun highLightButtonsInit() {
binding.apply {
reportTitleEt.let { title ->
@@ -251,9 +260,24 @@ class PrepareUploadFragment :
private fun initClickListeners(isSubmitEnabled: Boolean) {
binding.sendReportBtn.setOnClickListener {
- if (isSubmitEnabled) {
- } else {
- showSubmitReportErrorSnackBar()
+ binding.sendReportBtn.setOnClickListener {
+ if (isSubmitEnabled) {
+ val selectedFiles = filesRecyclerViewAdapter.getFiles()// however you get selected VaultFiles
+
+ if (selectedFiles.isNotEmpty()) {
+ viewModel.prepareUploadsFromVaultFiles(
+ files = selectedFiles,
+ ip = "",
+ port = "",
+ expectedFingerprint = "",
+ sessionId = ""
+ )
+ } else {
+ showToast("No file selected")
+ }
+ } else {
+ showSubmitReportErrorSnackBar()
+ }
}
}
}
From 95c3a5c1b32daa812d695ff315ed2ac40f40e1a7 Mon Sep 17 00:00:00 2001
From: wafa
Date: Mon, 2 Jun 2025 14:15:01 +0100
Subject: [PATCH 011/153] reformat code
---
.../mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 10ac430d0..45db49c7d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -28,9 +28,7 @@ import java.io.FileOutputStream
import java.net.Inet4Address
import java.net.NetworkInterface
import java.security.MessageDigest
-import java.util.UUID
import javax.inject.Inject
-import kotlin.jvm.Throws
@HiltViewModel
class PeerToPeerViewModel @Inject constructor(
@@ -168,6 +166,7 @@ class PeerToPeerViewModel @Inject constructor(
PeerSessionManager.sessionId = sessionId
// update UI state
_registrationSuccess.postValue(true)
+ }
}
}
From 86d46711808574f724f12c98e6e2e1631daf5802 Mon Sep 17 00:00:00 2001
From: wafa
Date: Mon, 2 Jun 2025 14:52:15 +0100
Subject: [PATCH 012/153] save connection Infos
---
.../fragment/peertopeer/PeerSessionManager.kt | 35 +++++++++++--------
.../peertopeer/PeerToPeerViewModel.kt | 5 +--
.../fragment/peertopeer/SenderViewModel.kt | 21 +++++------
.../senderflow/PrepareUploadFragment.kt | 11 ++----
4 files changed, 35 insertions(+), 37 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
index e28cfb07a..7bba9c878 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
@@ -4,23 +4,30 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
* Created by wafa on 2/6/2025.
*/
+data class PeerConnectionInfo(
+ val ip: String,
+ val port: String,
+ val expectedFingerprint: String,
+ val sessionId: String
+)
+
object PeerSessionManager {
- var ip: String? = null
- var port: String? = null
- var hash: String? = null
- var sessionId: String? = null
+ private var connectionInfo: PeerConnectionInfo? = null
- fun isSessionValid(): Boolean {
- return !ip.isNullOrEmpty() &&
- !port.isNullOrEmpty() &&
- !hash.isNullOrEmpty() &&
- !sessionId.isNullOrEmpty()
+ fun saveConnectionInfo(
+ ip: String,
+ port: String,
+ expectedFingerprint: String,
+ sessionId: String
+ ) {
+ connectionInfo = PeerConnectionInfo(ip, port, expectedFingerprint, sessionId)
}
+ fun getConnectionInfo(): PeerConnectionInfo? = connectionInfo
+
+ fun isSessionValid(): Boolean = connectionInfo != null
+
fun clear() {
- ip = null
- port = null
- hash = null
- sessionId = null
+ connectionInfo = null
}
-}
\ No newline at end of file
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 45db49c7d..8571977f6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -160,10 +160,7 @@ class PeerToPeerViewModel @Inject constructor(
val result = peerClient.registerPeerDevice(ip, port, hash, pin)
result.onSuccess { sessionId ->
Log.d("QRCode", "Registered successfully: $sessionId")
- PeerSessionManager.ip = ip
- PeerSessionManager.port = port
- PeerSessionManager.hash = hash
- PeerSessionManager.sessionId = sessionId
+ PeerSessionManager.saveConnectionInfo(ip, port, hash, sessionId)
// update UI state
_registrationSuccess.postValue(true)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index b6721ed77..7e0a8fd58 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -61,33 +61,33 @@ class SenderViewModel @Inject constructor(
fun prepareUploadsFromVaultFiles(
files: List,
- ip: String,
- port: String,
- expectedFingerprint: String,
- sessionId: String,
title: String = "Title of the report"
) {
+ val info = PeerSessionManager.getConnectionInfo() ?: run {
+ Timber.e("Connection info missing")
+ return
+ }
+
viewModelScope.launch {
val successfulResponses = mutableListOf()
for (file in files) {
val result = peerClient.prepareUpload(
- ip = ip,
- port = port,
- expectedFingerprint = expectedFingerprint,
+ ip = info.ip,
+ port = info.port,
+ expectedFingerprint = info.expectedFingerprint,
title = title,
file = File(file.path),
fileId = file.id,
sha256 = file.hash,
- sessionId = sessionId
+ sessionId = info.sessionId
)
result.onSuccess { transmissionId ->
Timber.d("Success: transmissionId = $transmissionId")
successfulResponses.add(PeerPrepareUploadResponse(transmissionId))
}.onFailure {
- Timber.e(it, "Failed to prepare upload")
- // You can log or ignore errors here — not returned to LiveData
+ Timber.e(it, "Failed to prepare upload for file: ${file.name}")
}
}
@@ -96,6 +96,7 @@ class SenderViewModel @Inject constructor(
}
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index d7f29e516..2adeb0d19 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -262,16 +262,9 @@ class PrepareUploadFragment :
binding.sendReportBtn.setOnClickListener {
binding.sendReportBtn.setOnClickListener {
if (isSubmitEnabled) {
- val selectedFiles = filesRecyclerViewAdapter.getFiles()// however you get selected VaultFiles
-
+ val selectedFiles = filesRecyclerViewAdapter.getFiles()
if (selectedFiles.isNotEmpty()) {
- viewModel.prepareUploadsFromVaultFiles(
- files = selectedFiles,
- ip = "",
- port = "",
- expectedFingerprint = "",
- sessionId = ""
- )
+ viewModel.prepareUploadsFromVaultFiles(selectedFiles)
} else {
showToast("No file selected")
}
From b276dbf0f8ad4b62b91e62127084727275c2ae88 Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 3 Jun 2025 19:52:34 +0100
Subject: [PATCH 013/153] wip prepareUpload flow and api change
---
.../tella/mobile/data/peertopeer/FileItem.kt | 4 +-
.../data/peertopeer/PrepareUploadRequest.kt | 5 +-
.../data/peertopeer/TellaPeerToPeerClient.kt | 105 +++++++++---------
.../data/peertopeer/TellaPeerToPeerServer.kt | 19 +---
.../tella/mobile/util/NavigationManager.kt | 9 +-
.../fragment/peertopeer/SenderViewModel.kt | 40 +++----
.../fragment/peertopeer/WaitingFragment.kt | 27 +++++
.../receipentflow/ConnectHotspotFragment.kt | 1 +
.../receipentflow/QRCodeFragment.kt | 7 ++
.../senderflow/PrepareUploadFragment.kt | 7 +-
.../senderflow/ScanQrCodeFragment.kt | 2 +-
.../src/main/res/layout/fragment_waiting.xml | 54 +++++++++
.../res/navigation/peer_to_peer_graph.xml | 14 ++-
13 files changed, 195 insertions(+), 99 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
create mode 100644 mobile/src/main/res/layout/fragment_waiting.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
index 1c0d3c2dd..8c4071fac 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
@@ -3,10 +3,10 @@ package org.horizontal.tella.mobile.data.peertopeer
import kotlinx.serialization.Serializable
@Serializable
-data class FileItem(
+data class P2PFile(
val id: String,
val fileName: String,
val size: Long,
val fileType: String,
val sha256: String
-)
\ No newline at end of file
+)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
index e6e8b9aa8..2653e826a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
@@ -1,10 +1,11 @@
package org.horizontal.tella.mobile.data.peertopeer
+import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class PrepareUploadRequest(
val title: String,
- val sessionId: String,
- val files: List
+ @SerialName("sessionId") val sessionId: String,
+ val files: List
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 01075581b..04d03cb4b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -1,6 +1,7 @@
package org.horizontal.tella.mobile.data.peertopeer
import android.util.Log
+import com.hzontal.tella_vault.VaultFile
import kotlinx.serialization.encodeToString
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -119,66 +120,66 @@ class TellaPeerToPeerClient {
ip: String,
port: String,
expectedFingerprint: String,
- title: String = "Title of the report",
- file: File,
- fileId: String,
- sha256: String,
+ title: String,
+ files: List,
sessionId: String
- ): Result {
- return withContext(Dispatchers.IO) {
- val url = "https://$ip:$port/api/v1/prepare-upload"
-
- val fileItem = FileItem(
- id = fileId,
- fileName = file.name,
- size = file.length(),
- fileType = "application/octet-stream",
- sha256 = sha256
+ ): Result = withContext(Dispatchers.IO) {
+ val url = "https://$ip:$port/api/v1/prepare-upload"
+
+ val fileItems = files.map {
+ P2PFile(
+ id = it.id,
+ fileName = it.name,
+ size = it.size,
+ fileType = "application/octet-stream", // or detect mime type
+ sha256 = it.hash
)
+ }
- val requestPayload = PrepareUploadRequest(
- title = title,
- sessionId = sessionId,
- files = listOf(fileItem)
- )
+ val requestPayload = PrepareUploadRequest(
+ title = title,
+ sessionId = sessionId,
+ files = fileItems
+ )
- val jsonPayload = Json.encodeToString(requestPayload)
- val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
- Log.d("PeerClient", "Request payload: $requestBody")
- val client = getClientWithFingerprintValidation(expectedFingerprint)
+ val jsonPayload = Json.encodeToString(requestPayload)
+ val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
+ val client = getClientWithFingerprintValidation(expectedFingerprint)
+
+ try {
+ val request = Request.Builder()
+ .url(url)
+ .post(requestBody)
+ .addHeader("Content-Type", "application/json")
+ .build()
- try {
- val request = Request.Builder()
- .url(url)
- .post(requestBody)
- .addHeader("Content-Type", "application/json")
- .build()
-
- client.newCall(request).execute().use { response ->
- if (response.isSuccessful) {
- val responseBody = response.body?.string()
- responseBody?.let {
- val jsonObject = JSONObject(it)
- val transmissionId = jsonObject.getString("transmissionId")
- Log.d("PrepareUpload", "Transmission ID: $transmissionId")
- return@use Result.success(transmissionId)
- }
- } else {
- Log.e("PrepareUpload", "Error ${response.code}: ${response.message}")
- when (response.code) {
- 409 -> {
- Log.e("PrepareUpload", "Conflict: Try canceling active sessions.")
- }
-
- else -> {}
- }
+ client.newCall(request).execute().use { response ->
+ val body = response.body?.string()
+
+ if (response.isSuccessful && body != null) {
+ return@use try {
+ val transmissionId = JSONObject(body).getString("transmissionId")
+ Result.success(transmissionId)
+ } catch (e: Exception) {
+ Log.e("PrepareUpload", "Invalid JSON response: $body", e)
+ Result.failure(Exception("Malformed server response"))
}
+ } else {
+ Log.e("PrepareUpload", "Server error ${response.code}: ${response.message}")
+ when (response.code) {
+ 400 -> Log.e("PrepareUpload", "Bad Request – likely missing or invalid fields.")
+ 409 -> Log.e("PrepareUpload", "Conflict – maybe another active session.")
+ 500 -> Log.e("PrepareUpload", "Internal Server Error – try again later.")
+ else -> Log.e("PrepareUpload", "Unhandled server error code.")
+ }
+ return@use Result.failure(Exception("Server returned error ${response.code}"))
}
- Result.failure(Exception("Unsuccessful response"))
- } catch (e: Exception) {
- Log.e("PrepareUpload", "Exception: ${e.message}", e)
- Result.failure(e)
}
+
+ Result.failure(Exception("No response from server"))
+ } catch (e: Exception) {
+ Log.e("PrepareUpload", "Exception during upload: ${e.message}", e)
+ Result.failure(e)
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index edb47fe4e..fb622bd3b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -14,6 +14,7 @@ import io.ktor.server.engine.sslConnector
import io.ktor.server.netty.Netty
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.request.receive
+import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.post
@@ -96,30 +97,22 @@ class TellaPeerToPeerServer(
HttpStatusCode.OK
)
}
-
-
post("/api/v1/prepare-upload") {
val request = try {
call.receive()
} catch (e: Exception) {
- call.respondText("Invalid body", status = HttpStatusCode.BadRequest)
+ call.respond(HttpStatusCode.BadRequest, "Invalid body: ${e.message}")
return@post
}
if (request.title.isBlank() || request.sessionId.isBlank() || request.files.isEmpty()) {
- call.respondText(
- "Missing required fields",
- status = HttpStatusCode.BadRequest
- )
+ call.respond(HttpStatusCode.BadRequest, "Missing required fields")
return@post
}
-
- // we can process the files or store metadata here
val transmissionId = UUID.randomUUID().toString()
- call.respondText(
- Gson().toJson(PeerPrepareUploadResponse(transmissionId)),
- ContentType.Application.Json,
- HttpStatusCode.OK
+ call.respond(
+ HttpStatusCode.OK,
+ PeerPrepareUploadResponse(transmissionId)
)
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index 528ebe74e..ca7a91f1e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -184,11 +184,18 @@ class NavigationManager(
fun navigateFromScanQrCodeToDeviceInfo() {
navigateToWithBundle(R.id.action_qrCodeScreen_to_deviceInfoScreen)
}
- fun navigateFromScanQrCodeTo() {
+ fun navigateFromScanQrCodeToPrepareUploadFragment() {
navigateToWithBundle(R.id.action_scanQrCodeScreen_to_prepareUploadFragment)
}
fun navigateFromScanQrCodeToSenderManualConnectionScreen() {
navigateToWithBundle(R.id.action_scanQrCodeScreen_to_senderManualConnectionScreen)
}
+ fun navigateFromQrCodeScreenToWaitingFragment() {
+ navigateToWithBundle(R.id.action_qrCodeScreen_to_waitingFragment)
+ }
+
+ fun navigateFromPrepareUploadFragmentToWaitingFragment() {
+ navigateToWithBundle(R.id.action_prepareUploadFragment_to_waitingFragment)
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 7e0a8fd58..8b399337e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -26,8 +26,8 @@ import javax.inject.Inject
class SenderViewModel @Inject constructor(
private val peerClient: TellaPeerToPeerClient
) : ViewModel() {
- private val _prepareResults = MutableLiveData>()
- val prepareResults: LiveData> = _prepareResults
+ private val _prepareResults = MutableLiveData()
+ val prepareResults: LiveData = _prepareResults
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
@@ -69,34 +69,26 @@ class SenderViewModel @Inject constructor(
}
viewModelScope.launch {
- val successfulResponses = mutableListOf()
+ val result = peerClient.prepareUpload(
+ ip = info.ip,
+ port = info.port,
+ expectedFingerprint = info.expectedFingerprint,
+ title = title,
+ files = files,
+ sessionId = info.sessionId
+ )
- for (file in files) {
- val result = peerClient.prepareUpload(
- ip = info.ip,
- port = info.port,
- expectedFingerprint = info.expectedFingerprint,
- title = title,
- file = File(file.path),
- fileId = file.id,
- sha256 = file.hash,
- sessionId = info.sessionId
- )
-
- result.onSuccess { transmissionId ->
- Timber.d("Success: transmissionId = $transmissionId")
- successfulResponses.add(PeerPrepareUploadResponse(transmissionId))
- }.onFailure {
- Timber.e(it, "Failed to prepare upload for file: ${file.name}")
- }
+ result.onSuccess { transmissionId ->
+ Timber.d("Success: transmissionId = $transmissionId")
+ _prepareResults.postValue(PeerPrepareUploadResponse(transmissionId))
+ }.onFailure { error ->
+ Timber.e(error, "Failed to prepare upload for ${files.size} files")
+ // Optionally post a failure state to LiveData if needed
}
-
- _prepareResults.postValue(successfulResponses)
}
}
-
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
new file mode 100644
index 000000000..62bfe5492
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -0,0 +1,27 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+import android.os.Bundle
+import android.view.View
+import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+
+/**
+ * Created by wafa on 3/6/2025.
+ */
+class WaitingFragment : BaseBindingFragment(FragmentWaitingBinding::inflate){
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ val isSender = arguments?.getBoolean("isSender") ?: false
+
+ if (isSender) {
+ binding.waitingText.text = "Waiting for the sender to share files"
+ } else {
+ binding.waitingText.text = "Waiting for the recipient to accept files"
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index b2f5e9ed2..4331fb4fe 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -57,6 +57,7 @@ class ConnectHotspotFragment :
binding.nextBtn.setOnClickListener { }
binding.backBtn.setOnClickListener { baseActivity.onBackPressed() }
+
}
private fun updateNextButtonState(connectionType: ConnectionType?) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index a0efe6c9a..70e38c04f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -35,6 +35,13 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
}
handleBack()
handleConnectManually()
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingFragment()
+ } else {
+ }
+ }
}
private fun setupServerAndQr(ip: String) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 2adeb0d19..a7629e52c 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -89,11 +89,9 @@ class PrepareUploadFragment :
isNewDraft = false
}
- viewModel.prepareResults.observe(viewLifecycleOwner) { responses ->
- responses.forEach { response ->
+ viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
val id = response.transmissionId
// navigate to next screen
- }
}
highLightButtonsInit()
checkIsNewDraftEntry()
@@ -265,6 +263,9 @@ class PrepareUploadFragment :
val selectedFiles = filesRecyclerViewAdapter.getFiles()
if (selectedFiles.isNotEmpty()) {
viewModel.prepareUploadsFromVaultFiles(selectedFiles)
+ // navigate to waiting view
+ bundle.putBoolean("isSender", true)
+ navManager().navigateFromPrepareUploadFragmentToWaitingFragment()
} else {
showToast("No file selected")
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 27938c6dc..cc39341ee 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -35,7 +35,7 @@ class ScanQrCodeFragment :
barcodeView = binding.qrCodeScanView
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- navManager().navigateFromScanQrCodeTo()
+ navManager().navigateFromScanQrCodeToPrepareUploadFragment()
} else {
// handle error UI
}
diff --git a/mobile/src/main/res/layout/fragment_waiting.xml b/mobile/src/main/res/layout/fragment_waiting.xml
new file mode 100644
index 000000000..43f87cad7
--- /dev/null
+++ b/mobile/src/main/res/layout/fragment_waiting.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 046e4ed78..8e604430e 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -58,6 +58,9 @@
+
+ tools:layout="@layout/fragment_prepare_upload" >
+
+
+
\ No newline at end of file
From e9507aebe98373145540f0ff338380bbe6137e25 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 3 Jun 2025 21:53:55 +0100
Subject: [PATCH 014/153] wip manual connection
---
mobile/build.gradle | 2 +
.../data/peertopeer/FingerprintFetcher.kt | 2 +-
.../data/peertopeer/PeerToPeerManager.kt | 13 ++++
.../mobile/data/peertopeer/ServerPinger.kt | 31 ++++++++++
.../data/peertopeer/TellaPeerToPeerServer.kt | 16 ++++-
.../tella/mobile/util/NavigationManager.kt | 8 +++
.../fragment/peertopeer/PeerSessionManager.kt | 10 +--
.../peertopeer/PeerToPeerViewModel.kt | 62 +++++++------------
.../fragment/peertopeer/di/PeerModule.kt | 7 +++
.../receipentflow/QRCodeFragment.kt | 16 +++--
.../RecipientVerificationFragment.kt | 14 +++--
.../receipentflow/ShowDeviceInfoFragment.kt | 24 +++++++
.../SenderManualConnectionFragment.kt | 20 +++++-
.../senderflow/SenderVerificationFragment.kt | 18 +++---
.../res/navigation/peer_to_peer_graph.xml | 6 +-
15 files changed, 183 insertions(+), 66 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerManager.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/ServerPinger.kt
diff --git a/mobile/build.gradle b/mobile/build.gradle
index 82690e516..6b98157d2 100644
--- a/mobile/build.gradle
+++ b/mobile/build.gradle
@@ -243,6 +243,8 @@ dependencies {
implementation("io.ktor:ktor-server-netty:2.3.9")
implementation("io.ktor:ktor-server-content-negotiation:2.3.9")
implementation("io.ktor:ktor-server-cio:2.3.9")
+ implementation "io.ktor:ktor-server-call-logging:2.3.9" // or your current version
+
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3' // Use the latest version
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt
index d36c87530..fbe1832d3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FingerprintFetcher.kt
@@ -37,7 +37,7 @@ object FingerprintFetcher {
return socket
}
- private class TrustAllCerts : X509TrustManager {
+ class TrustAllCerts : X509TrustManager {
override fun checkClientTrusted(chain: Array, authType: String) {}
override fun checkServerTrusted(chain: Array, authType: String) {}
override fun getAcceptedIssuers(): Array = arrayOf()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerManager.kt
new file mode 100644
index 000000000..b38314cb8
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerManager.kt
@@ -0,0 +1,13 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+
+class PeerToPeerManager {
+ private val _clientConnected = MutableSharedFlow(replay = 0)
+ val clientConnected = _clientConnected.asSharedFlow()
+
+ suspend fun notifyClientConnected(hash : String) {
+ _clientConnected.emit(hash)
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/ServerPinger.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/ServerPinger.kt
new file mode 100644
index 000000000..43a8acbad
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/ServerPinger.kt
@@ -0,0 +1,31 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody
+import java.security.SecureRandom
+import javax.net.ssl.SSLContext
+
+object ServerPinger {
+ fun notifyServer(ip: String, port: Int) {
+ val trustAllCerts = FingerprintFetcher.TrustAllCerts()
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(null, arrayOf(trustAllCerts), SecureRandom())
+
+ val client = OkHttpClient.Builder()
+ .sslSocketFactory(sslContext.socketFactory, trustAllCerts)
+ .hostnameVerifier { _, _ -> true }
+ .build()
+
+ val request = Request.Builder()
+ .url("https://$ip:$port/api/v1/ping")
+ .post(RequestBody.create(null, ByteArray(0)))
+ .build()
+
+ client.newCall(request).execute().use { response ->
+ if (!response.isSuccessful) {
+ throw RuntimeException("Failed to notify server: ${response.code}")
+ }
+ }
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index fb622bd3b..52811c5db 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -16,9 +16,13 @@ import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
+import io.ktor.server.plugins.callloging.CallLogging
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
@@ -37,7 +41,8 @@ class TellaPeerToPeerServer(
private val serverPort: Int = port,
private val keyPair: KeyPair,
private val certificate: X509Certificate,
- private val keyStoreConfig: KeyStoreConfig
+ private val keyStoreConfig: KeyStoreConfig,
+ private val peerToPeerManager: PeerToPeerManager
) : TellaServer {
private var engine: ApplicationEngine? = null
@@ -57,6 +62,7 @@ class TellaPeerToPeerServer(
}
engine = embeddedServer(Netty, environment = applicationEngineEnvironment {
+ var firstConnectionReceived = false
sslConnector(
keyStore = keyStore,
keyAlias = keyStoreConfig.alias,
@@ -78,6 +84,14 @@ class TellaPeerToPeerServer(
call.respondText("The server is running securely over HTTPS.")
}
+ post("/api/v1/ping") {
+ val hash = CertificateUtils.getPublicKeyHash(certificate)
+ CoroutineScope(Dispatchers.IO).launch {
+ peerToPeerManager.notifyClientConnected(hash)
+ }
+ call.respondText("pong", status = HttpStatusCode.OK)
+ }
+
post("/api/v1/register") {
val request = try {
call.receive()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index ca7a91f1e..dc8ac233a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -191,6 +191,14 @@ class NavigationManager(
fun navigateFromScanQrCodeToSenderManualConnectionScreen() {
navigateToWithBundle(R.id.action_scanQrCodeScreen_to_senderManualConnectionScreen)
}
+
+ fun navigateFromSenderManualConnectionToConnectManuallyVerification() {
+ navigateToWithBundle(R.id.action_senderManualConnectionScreen_to_connectManuallyVerificationScreen)
+ }
+
+ fun navigateFromDeviceInfoScreenTRecipientVerificationScreen(){
+ navigateToWithBundle(R.id.action_deviceInfoScreen_to_recipientVerificationScreen)
+ }
fun navigateFromQrCodeScreenToWaitingFragment() {
navigateToWithBundle(R.id.action_qrCodeScreen_to_waitingFragment)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
index 7bba9c878..b5f8caa3e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
@@ -5,10 +5,12 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
*/
data class PeerConnectionInfo(
- val ip: String,
- val port: String,
- val expectedFingerprint: String,
- val sessionId: String
+ val ip: String = "",
+ val port: String = "",
+ val expectedFingerprint: String = "",
+ val sessionId: String = "",
+ val hash: String = "",
+ val pin: Int = 0
)
object PeerSessionManager {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 8571977f6..6843e6a31 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -17,23 +17,25 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
+import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.NetworkInfo
import timber.log.Timber
-import java.io.File
-import java.io.FileOutputStream
import java.net.Inet4Address
import java.net.NetworkInterface
-import java.security.MessageDigest
import javax.inject.Inject
@HiltViewModel
class PeerToPeerViewModel @Inject constructor(
@ApplicationContext private val context: Context,
- private val peerClient: TellaPeerToPeerClient
+ private val peerClient: TellaPeerToPeerClient,
+ private val peerToPeerManager: PeerToPeerManager
) : ViewModel() {
private val _networkInfo = MutableLiveData()
@@ -45,6 +47,11 @@ class PeerToPeerViewModel @Inject constructor(
val getHashSuccess: LiveData get() = _getHashSuccess
private val _getHashError = MutableLiveData()
val getHashError: LiveData get() = _getHashError
+ private val _sessionInfo = MutableStateFlow(null)
+ val sessionInfo: StateFlow = _sessionInfo
+
+ val clientHash = peerToPeerManager.clientConnected
+
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("MissingPermission", "DiscouragedPrivateApi")
@@ -159,7 +166,6 @@ class PeerToPeerViewModel @Inject constructor(
viewModelScope.launch {
val result = peerClient.registerPeerDevice(ip, port, hash, pin)
result.onSuccess { sessionId ->
- Log.d("QRCode", "Registered successfully: $sessionId")
PeerSessionManager.saveConnectionInfo(ip, port, hash, sessionId)
// update UI state
_registrationSuccess.postValue(true)
@@ -172,47 +178,25 @@ class PeerToPeerViewModel @Inject constructor(
val result = FingerprintFetcher.fetch(ip, port.toInt())
result.onSuccess { hash ->
- _getHashSuccess.postValue(hash)
Timber.d("hash ***** $hash")
+ _getHashSuccess.postValue(hash)
+
+ // Notify the server after fetching the hash
+ runCatching {
+ ServerPinger.notifyServer(ip, port.toInt())
+ }.onFailure {
+ Timber.e(it, "Failed to ping server after fetching hash")
+ }
+
}.onFailure { error ->
- _getHashError.postValue(error)
Timber.d("error ***** $error")
+ _getHashError.postValue(error)
}
-
}
}
- private fun createFileFromAsset(context: Context, assetFileName: String): File {
- // Create a temporary file in the cache directory
- val tempFile = File(context.cacheDir, assetFileName)
-
- if (!tempFile.exists()) {
- Log.e("PrepareUpload", "File does not exist: ${tempFile.absolutePath}")
- }
-
- // Open the asset file
- context.assets.open(assetFileName).use { inputStream ->
- // Write the content of the asset to the temporary file
- FileOutputStream(tempFile).use { outputStream ->
- inputStream.copyTo(outputStream)
- }
- }
-
- return tempFile
+ fun setPeerSessionInfo(info: PeerConnectionInfo) {
+ _sessionInfo.value = info
}
-
- private fun calculateSha256(file: File): String {
- val digest = MessageDigest.getInstance("SHA-256")
- file.inputStream().use { input ->
- val buffer = ByteArray(8192)
- var bytesRead: Int
- while (input.read(buffer).also { bytesRead = it } != -1) {
- digest.update(buffer, 0, bytesRead)
- }
- }
- return digest.digest().joinToString("") { "%02x".format(it) }
- }
-
-
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
index fefe59992..f47f324c3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
@@ -4,6 +4,7 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
+import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import javax.inject.Singleton
@@ -16,4 +17,10 @@ object PeerModule {
fun providePeerClient(): TellaPeerToPeerClient {
return TellaPeerToPeerClient()
}
+
+ @Provides
+ @Singleton
+ fun providePeerToPeerManager(): PeerToPeerManager {
+ return PeerToPeerManager()
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 70e38c04f..d97b8f180 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -4,12 +4,15 @@ import android.graphics.Bitmap
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
import com.google.zxing.BarcodeFormat
import com.google.zxing.WriterException
import com.journeyapps.barcodescanner.BarcodeEncoder
+import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.certificate.CertificateGenerator
import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerManager
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerServer
import org.horizontal.tella.mobile.data.peertopeer.port
@@ -18,7 +21,9 @@ import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import javax.inject.Inject
+@AndroidEntryPoint
class QRCodeFragment : BaseBindingFragment(FragmentQrCodeBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
@@ -26,6 +31,9 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
private var payload: PeerConnectionPayload? = null
private lateinit var qrPayload: String
+ @Inject
+ lateinit var peerToPeerManager: PeerToPeerManager
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -52,7 +60,8 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
ip = ip,
keyPair = keyPair,
certificate = certificate,
- keyStoreConfig = config
+ keyStoreConfig = config,
+ peerToPeerManager = peerToPeerManager
)
server?.start()
@@ -92,7 +101,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
binding.backBtn.setOnClickListener { nav().popBackStack() }
}
- private fun handleConnectManually(){
+ private fun handleConnectManually() {
binding.connectManuallyButton.setOnClickListener {
connectManually()
}
@@ -105,8 +114,5 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
}
}
- // TODO NEXT STEPS
- //TODO WORK ON THE SENDER RESPONER
- // TODO PREAPRE REGISTER RESPONE
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 9537fb46b..96b1d1c12 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -2,14 +2,17 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
-class RecipientVerificationFragment:
+class RecipientVerificationFragment :
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
-
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
private var payload: PeerConnectionPayload? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -22,10 +25,13 @@ class RecipientVerificationFragment:
}
private fun initView() {
-
+ lifecycleScope.launchWhenStarted {
+ viewModel.sessionInfo.collect { session ->
+ binding.hashContentTextView.text = session?.hash
+ }
+ }
}
private fun initListeners() {
-
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 354b39ac7..8aac3a8c2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -2,16 +2,23 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
+import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.databinding.ShowDeviceInfoLayoutBinding
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
class ShowDeviceInfoFragment :
BaseBindingFragment(ShowDeviceInfoLayoutBinding::inflate) {
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
private var payload: PeerConnectionPayload? = null
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
arguments?.getString("payload")?.let { payloadJson ->
@@ -19,6 +26,7 @@ class ShowDeviceInfoFragment :
}
initListeners()
initView()
+ initObservers()
}
private fun initView() {
@@ -28,6 +36,22 @@ class ShowDeviceInfoFragment :
}
private fun initListeners() {
+ binding.backBtn.setOnClickListener { back() }
+ }
+ private fun initObservers() {
+ lifecycleScope.launch {
+ viewModel.clientHash.collect { hash ->
+ viewModel.setPeerSessionInfo(
+ PeerConnectionInfo(
+ ip = payload?.connectCode.toString(),
+ port = payload?.port.toString(),
+ pin = payload?.pin?.toInt()!!,
+ hash = hash
+ )
+ )
+ navManager().navigateFromDeviceInfoScreenTRecipientVerificationScreen()
+ }
+ }
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index 75f5e3e22..4e2f08d43 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -7,6 +7,7 @@ import androidx.fragment.app.activityViewModels
import com.hzontal.tella_locking_ui.common.extensions.onChange
import org.horizontal.tella.mobile.databinding.SenderManualConnectionBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
import org.hzontal.shared_ui.bottomsheet.KeyboardUtil
@@ -34,6 +35,8 @@ class SenderManualConnectionFragment :
updateNextButtonState()
}
+ initObservers()
+
updateNextButtonState()
KeyboardUtil(binding.root)
@@ -66,6 +69,18 @@ class SenderManualConnectionFragment :
)
)
binding.nextBtn.setOnClickListener {
+ val ip = binding.connectCode.text.toString()
+ val port = binding.port.text.toString()
+ val pin = binding.pin.text.toString()
+
+ viewModel.setPeerSessionInfo(
+ PeerConnectionInfo(
+ ip = ip,
+ port = port,
+ pin = pin.toInt()
+ )
+ ) // Store values
+
viewModel.handleCertificate(
ip = binding.connectCode.text.toString(),
port = binding.port.text.toString(),
@@ -76,10 +91,13 @@ class SenderManualConnectionFragment :
private fun initObservers() {
viewModel.getHashSuccess.observe(viewLifecycleOwner) { hash ->
+ bundle.putString("hash", hash)
+ viewModel.setPeerSessionInfo(PeerConnectionInfo(hash = hash))
+ navManager().navigateFromSenderManualConnectionToConnectManuallyVerification()
}
- viewModel.getHashError.observe(viewLifecycleOwner) { error->
+ viewModel.getHashError.observe(viewLifecycleOwner) { error ->
error.localizedMessage?.let { showToast(it) }
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 9c322db74..3eecfc653 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -2,22 +2,19 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
import android.os.Bundle
import android.view.View
-import com.google.gson.Gson
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
-import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
class SenderVerificationFragment :
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
-
- private var payload: PeerConnectionPayload? = null
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- arguments?.getString("payload")?.let { payloadJson ->
- payload = Gson().fromJson(payloadJson, PeerConnectionPayload::class.java)
- }
initListeners()
initView()
}
@@ -25,9 +22,14 @@ class SenderVerificationFragment :
private fun initView() {
binding.titleDescTextView.text = getString(R.string.make_sure_sequence_matches_recipient)
binding.warningTextView.text = getString(R.string.sequence_mismatch_warning_recipient)
+
}
private fun initListeners() {
-
+ lifecycleScope.launchWhenStarted {
+ viewModel.sessionInfo.collect { session ->
+ binding.hashContentTextView.text = session?.hash
+ }
+ }
}
}
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 8e604430e..0d63e55da 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -33,8 +33,8 @@
Date: Wed, 4 Jun 2025 00:20:07 +0100
Subject: [PATCH 015/153] WIP manual connection
---
.../fragment/peertopeer/PeerToPeerViewModel.kt | 3 +--
.../peertopeer/receipentflow/QRCodeFragment.kt | 18 +++++++++++-------
.../receipentflow/ShowDeviceInfoFragment.kt | 8 ++++++++
.../senderflow/ScanQrCodeFragment.kt | 2 +-
.../SenderManualConnectionFragment.kt | 2 +-
.../senderflow/SenderVerificationFragment.kt | 14 ++++++++++++++
.../main/res/navigation/peer_to_peer_graph.xml | 4 ++--
7 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 6843e6a31..a20ad0f99 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -8,7 +8,6 @@ import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.os.Build
import android.text.format.Formatter
-import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.lifecycle.LiveData
@@ -162,7 +161,7 @@ class PeerToPeerViewModel @Inject constructor(
}
}
- fun onQrCodeParsed(ip: String, port: String, hash: String, pin: String) {
+ fun startRegistration(ip: String, port: String, hash: String, pin: String) {
viewModelScope.launch {
val result = peerClient.registerPeerDevice(ip, port, hash, pin)
result.onSuccess { sessionId ->
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index d97b8f180..1dd81d705 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -43,13 +43,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
}
handleBack()
handleConnectManually()
- viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
- if (success) {
- bundle.putBoolean("isSender", false)
- navManager().navigateFromQrCodeScreenToWaitingFragment()
- } else {
- }
- }
+ initObservers()
}
private fun setupServerAndQr(ip: String) {
@@ -114,5 +108,15 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
}
}
+ private fun initObservers() {
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingFragment()
+ } else {
+ }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 8aac3a8c2..6f964d8ba 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -53,5 +53,13 @@ class ShowDeviceInfoFragment :
navManager().navigateFromDeviceInfoScreenTRecipientVerificationScreen()
}
}
+
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingFragment()
+ } else {
+ }
+ }
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index cc39341ee..ede4244fa 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -65,7 +65,7 @@ class ScanQrCodeFragment :
try {
val payload = Gson().fromJson(qrContent, PeerConnectionPayload::class.java)
- viewModel.onQrCodeParsed(
+ viewModel.startRegistration(
ip = payload.connectCode,
port = payload.port.toString(),
hash = payload.certificateHash,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index 4e2f08d43..84d981cfc 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -91,7 +91,7 @@ class SenderManualConnectionFragment :
private fun initObservers() {
viewModel.getHashSuccess.observe(viewLifecycleOwner) { hash ->
- bundle.putString("hash", hash)
+ bundle.putString("payload", hash)
viewModel.setPeerSessionInfo(PeerConnectionInfo(hash = hash))
navManager().navigateFromSenderManualConnectionToConnectManuallyVerification()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 3eecfc653..2e16e3f8e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -7,11 +7,13 @@ import androidx.lifecycle.lifecycleScope
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
class SenderVerificationFragment :
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
+ private lateinit var peerConnectionInfo: PeerConnectionInfo
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -28,8 +30,20 @@ class SenderVerificationFragment :
private fun initListeners() {
lifecycleScope.launchWhenStarted {
viewModel.sessionInfo.collect { session ->
+ if (session != null) {
+ peerConnectionInfo = session
+ }
binding.hashContentTextView.text = session?.hash
}
}
+
+ binding.confirmAndConnectBtn.setOnClickListener {
+ viewModel.startRegistration(
+ ip = peerConnectionInfo.ip,
+ port = peerConnectionInfo.port,
+ hash = peerConnectionInfo.hash,
+ pin = peerConnectionInfo.pin.toString()
+ )
+ }
}
}
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 0d63e55da..99ebeaaff 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -7,7 +7,7 @@
From 49cd5b117eeb92823bc32a2cbc3b8a8367583ea1 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 4 Jun 2025 01:18:47 +0100
Subject: [PATCH 016/153] Finish manual connection
---
.../tella/mobile/util/NavigationManager.kt | 7 +++++++
.../peertopeer/PeerToPeerViewModel.kt | 3 +++
.../RecipientVerificationFragment.kt | 13 +++++++++++++
.../senderflow/PrepareUploadFragment.kt | 1 -
.../senderflow/ScanQrCodeFragment.kt | 19 ++++++++++++-------
.../SenderManualConnectionFragment.kt | 9 ++++++++-
.../senderflow/SenderVerificationFragment.kt | 11 +++++++++++
.../res/navigation/peer_to_peer_graph.xml | 16 ++++++++++++----
8 files changed, 66 insertions(+), 13 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index dc8ac233a..ce138964b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -206,4 +206,11 @@ class NavigationManager(
fun navigateFromPrepareUploadFragmentToWaitingFragment() {
navigateToWithBundle(R.id.action_prepareUploadFragment_to_waitingFragment)
}
+
+ fun navigateConnectManuallyVerificationFragmentToprepareUploadFragment(){
+ navigateToWithBundle(R.id.action_connectManuallyVerificationFragment_to_prepareUploadFragment)
+ }
+ fun navigateFromRecipientVerificationScreenToWaitingFragment(){
+ navigateToWithBundle(R.id.action_recipientVerificationScreen_to_waitingFragment)
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index a20ad0f99..33c6003a3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -168,6 +168,9 @@ class PeerToPeerViewModel @Inject constructor(
PeerSessionManager.saveConnectionInfo(ip, port, hash, sessionId)
// update UI state
_registrationSuccess.postValue(true)
+ }.onFailure { error ->
+ Timber.d("error ***** $error")
+
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 96b1d1c12..4c778965e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -33,5 +33,18 @@ class RecipientVerificationFragment :
}
private fun initListeners() {
+ binding.confirmAndConnectBtn.setOnClickListener {
+
+ }
+ }
+
+ private fun initObservers() {
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
+ } else {
+ }
+ }
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index a7629e52c..31af1c567 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -14,7 +14,6 @@ import com.hzontal.tella_vault.VaultFile
import com.hzontal.tella_vault.filter.FilterType
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.R
-import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.databinding.FragmentPrepareUploadBinding
import org.horizontal.tella.mobile.domain.entity.reports.ReportInstance
import org.horizontal.tella.mobile.media.MediaFileHandler
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index ede4244fa..99e265911 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -33,13 +33,7 @@ class ScanQrCodeFragment :
barcodeView = CompoundBarcodeView(requireContext())
barcodeView = binding.qrCodeScanView
- viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
- if (success) {
- navManager().navigateFromScanQrCodeToPrepareUploadFragment()
- } else {
- // handle error UI
- }
- }
+
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
@@ -53,6 +47,7 @@ class ScanQrCodeFragment :
}
handleBack()
initListeners()
+ initObservers()
}
private fun startScanning() {
@@ -120,4 +115,14 @@ class ScanQrCodeFragment :
navManager().navigateFromScanQrCodeToSenderManualConnectionScreen()
}
}
+
+ private fun initObservers(){
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ navManager().navigateFromScanQrCodeToPrepareUploadFragment()
+ } else {
+ // handle error UI
+ }
+ }
+ }
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index 84d981cfc..b6ab840a0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -92,7 +92,14 @@ class SenderManualConnectionFragment :
private fun initObservers() {
viewModel.getHashSuccess.observe(viewLifecycleOwner) { hash ->
bundle.putString("payload", hash)
- viewModel.setPeerSessionInfo(PeerConnectionInfo(hash = hash))
+ viewModel.setPeerSessionInfo(
+ PeerConnectionInfo(
+ ip = binding.connectCode.text.toString(),
+ port = binding.port.text.toString(),
+ pin = binding.pin.text.toString().toInt(),
+ hash = hash
+ )
+ )
navManager().navigateFromSenderManualConnectionToConnectManuallyVerification()
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 2e16e3f8e..955d23e60 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -19,6 +19,7 @@ class SenderVerificationFragment :
super.onViewCreated(view, savedInstanceState)
initListeners()
initView()
+ initObservers()
}
private fun initView() {
@@ -46,4 +47,14 @@ class SenderVerificationFragment :
)
}
}
+
+ private fun initObservers() {
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ navManager().navigateConnectManuallyVerificationFragmentToprepareUploadFragment()
+ } else {
+ // handle error UI
+ }
+ }
+ }
}
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 99ebeaaff..7ecf1943f 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -7,7 +7,7 @@
+ tools:layout="@layout/connect_manually_verification" >
+
+
+ tools:layout="@layout/connect_manually_verification">
+
+
From 7e38153ae42bac5e9284a9e77623205f45ca56b5 Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 4 Jun 2025 10:19:22 +0100
Subject: [PATCH 017/153] wip navigation based on event emitted in the server
api
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 10 ++++++
.../fragment/peertopeer/PeerEventManager.kt | 34 +++++++++++++++++++
.../peertopeer/PeerToPeerViewModel.kt | 27 ++++++++++++++-
.../fragment/peertopeer/WaitingFragment.kt | 2 +-
.../receipentflow/QRCodeFragment.kt | 10 ++++++
5 files changed, 81 insertions(+), 2 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 52811c5db..5b85fdcf6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -20,6 +20,8 @@ import io.ktor.server.plugins.callloging.CallLogging
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -29,6 +31,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.domain.peertopeer.PeerResponse
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerEventManager
import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
@@ -105,11 +108,18 @@ class TellaPeerToPeerServer(
}
val sessionId = UUID.randomUUID().toString()
+
+ // Emit registration success event asynchronously
+ launch {
+ PeerEventManager.emitRegistrationSuccess()
+ }
+
call.respondText(
Gson().toJson(PeerResponse(sessionId)),
ContentType.Application.Json,
HttpStatusCode.OK
)
+
}
post("/api/v1/prepare-upload") {
val request = try {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
new file mode 100644
index 000000000..ae74c10cc
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
@@ -0,0 +1,34 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+import io.ktor.http.HttpStatusCode
+import io.ktor.server.application.ApplicationCall
+import io.ktor.server.response.respond
+import kotlinx.coroutines.flow.MutableSharedFlow
+import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
+
+/**
+ * Created by wafa on 3/6/2025.
+ */
+object PeerEventManager {
+
+ // MutableSharedFlow to emit registration events, replay 1 to send last event to new collectors
+ val registrationEvents = MutableSharedFlow(replay = 1)
+
+ // Call this when registration succeeds
+ suspend fun emitRegistrationSuccess() {
+ registrationEvents.emit(true)
+ }
+
+ // we can add emitRegistrationFailure or other event types if needed
+
+
+ val prepareUploadEvents =
+ MutableSharedFlow Unit>>(replay = 0)
+
+ suspend fun emitPrepareUploadRequest(
+ request: PrepareUploadRequest,
+ callback: (Boolean) -> Unit
+ ) {
+ prepareUploadEvents.emit(request to callback)
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 33c6003a3..a519cf3f5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -20,14 +20,18 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
+import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.NetworkInfo
import timber.log.Timber
import java.net.Inet4Address
import java.net.NetworkInterface
+import java.security.MessageDigest
+import java.util.UUID
import javax.inject.Inject
@HiltViewModel
@@ -48,10 +52,32 @@ class PeerToPeerViewModel @Inject constructor(
val getHashError: LiveData get() = _getHashError
private val _sessionInfo = MutableStateFlow(null)
val sessionInfo: StateFlow = _sessionInfo
+ private val _registrationServerSuccess = MutableLiveData()
+ val registrationServerSuccess: LiveData = _registrationServerSuccess
+ private val _incomingUploadRequest = MutableLiveData()
+ val incomingUploadRequest: LiveData = _incomingUploadRequest
val clientHash = peerToPeerManager.clientConnected
+ init {
+ viewModelScope.launch {
+ PeerEventManager.incomingUploadRequests.collect { request ->
+ _incomingUploadRequest.postValue(request)
+ }
+ }
+ }
+
+ init {
+ viewModelScope.launch {
+ PeerEventManager.registrationEvents.collect { success ->
+ _registrationServerSuccess.postValue(success)
+ }
+ }
+ }
+ fun resetRegistrationState() {
+ _registrationServerSuccess.postValue(false)
+ }
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("MissingPermission", "DiscouragedPrivateApi")
fun fetchCurrentNetworkInfo() {
@@ -178,7 +204,6 @@ class PeerToPeerViewModel @Inject constructor(
fun handleCertificate(ip: String, port: String, pin: String) {
viewModelScope.launch {
val result = FingerprintFetcher.fetch(ip, port.toInt())
-
result.onSuccess { hash ->
Timber.d("hash ***** $hash")
_getHashSuccess.postValue(hash)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
index 62bfe5492..1e7327214 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -17,7 +17,7 @@ class WaitingFragment : BaseBindingFragment(FragmentWait
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val isSender = arguments?.getBoolean("isSender") ?: false
- if (isSender) {
+ if (!isSender) {
binding.waitingText.text = "Waiting for the sender to share files"
} else {
binding.waitingText.text = "Waiting for the recipient to accept files"
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 1dd81d705..131e0b7b4 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -43,6 +43,16 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
}
handleBack()
handleConnectManually()
+ viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ // Navigate to the next screen
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingFragment()
+ // reset the LiveData state if we want to consume event once
+ viewModel.resetRegistrationState()
+ } else {
+ }
+ }
initObservers()
}
From 79cd1e22294921ed9ec706708a85498c66234ffc Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 4 Jun 2025 10:24:21 +0100
Subject: [PATCH 018/153] comment the prepareUploadEvent
---
.../fragment/peertopeer/PeerToPeerViewModel.kt | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index a519cf3f5..98c86766e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -60,13 +60,13 @@ class PeerToPeerViewModel @Inject constructor(
val clientHash = peerToPeerManager.clientConnected
- init {
- viewModelScope.launch {
- PeerEventManager.incomingUploadRequests.collect { request ->
- _incomingUploadRequest.postValue(request)
- }
- }
- }
+// init {
+// viewModelScope.launch {
+// PeerEventManager.incomingUploadRequests.collect { request ->
+// _incomingUploadRequest.postValue(request)
+// }
+// }
+// }
init {
viewModelScope.launch {
From a7f6f4b94a9238b1589c75060c973c292b25a462 Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 4 Jun 2025 10:51:48 +0100
Subject: [PATCH 019/153] add the accept or reject files view and its
navigation
---
.../tella/mobile/util/NavigationManager.kt | 3 +
.../fragment/peertopeer/WaitingFragment.kt | 5 +-
.../receipentflow/RecipientSuccessFragment.kt | 24 +++++
mobile/src/main/res/drawable/ic_files.xml | 31 +++++++
.../res/layout/fragment_recipient_success.xml | 91 +++++++++++++++++++
.../res/navigation/peer_to_peer_graph.xml | 15 ++-
mobile/src/main/res/values/strings.xml | 1 +
7 files changed, 168 insertions(+), 2 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
create mode 100644 mobile/src/main/res/drawable/ic_files.xml
create mode 100644 mobile/src/main/res/layout/fragment_recipient_success.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index ce138964b..ba8d69358 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -213,4 +213,7 @@ class NavigationManager(
fun navigateFromRecipientVerificationScreenToWaitingFragment(){
navigateToWithBundle(R.id.action_recipientVerificationScreen_to_waitingFragment)
}
+ fun navigateFromWaitingFragmentToRecipientSuccessFragment(){
+ navigateToWithBundle(R.id.action_waitingFragment_to_recipientSuccessFragment)
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
index 1e7327214..6a8f91469 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -2,6 +2,7 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import android.os.Bundle
import android.view.View
+import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
@@ -18,8 +19,10 @@ class WaitingFragment : BaseBindingFragment(FragmentWait
val isSender = arguments?.getBoolean("isSender") ?: false
if (!isSender) {
- binding.waitingText.text = "Waiting for the sender to share files"
+ binding.toolbar.setToolbarTitle(getString(R.string.receive_files))
+ binding.waitingText.text = getString(R.string.waiting_for_the_sender_to_share_files)
} else {
+ binding.toolbar.setToolbarTitle(getString(R.string.send_files))
binding.waitingText.text = "Waiting for the recipient to accept files"
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
new file mode 100644
index 000000000..73731a4e8
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -0,0 +1,24 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+import android.os.Bundle
+import android.view.View
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
+import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+
+/**
+ * Created by wafa on 3/6/2025.
+ */
+class RecipientSuccessFragment : BaseBindingFragment(FragmentRecipientSuccessBinding::inflate){
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/res/drawable/ic_files.xml b/mobile/src/main/res/drawable/ic_files.xml
new file mode 100644
index 000000000..684c3c57b
--- /dev/null
+++ b/mobile/src/main/res/drawable/ic_files.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/src/main/res/layout/fragment_recipient_success.xml b/mobile/src/main/res/layout/fragment_recipient_success.xml
new file mode 100644
index 000000000..2024ba579
--- /dev/null
+++ b/mobile/src/main/res/layout/fragment_recipient_success.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 7ecf1943f..1442900e1 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -111,6 +111,19 @@
android:id="@+id/waitingFragment"
android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.WaitingFragment"
tools:layout="@layout/fragment_waiting"
- android:label="WaitingFragment" />
+ android:label="WaitingFragment" >
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index e98c87573..f157f071e 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1040,4 +1040,5 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Make sure that this sequence matches what is shown on the recipient’s device.
If the sequence on your device does not match the sequence on the recipient’s device, the connection may not be secure and should be discarded.
Discard and start over
+ Waiting for the sender to share files
From 5391b8aa679cf4691d67c1332895129e8372f57f Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 4 Jun 2025 11:17:57 +0100
Subject: [PATCH 020/153] clean flow
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 4 +-
.../managers/PeerServerStarterManager.kt | 41 +++++++++++++++++++
.../{ => managers}/PeerToPeerManager.kt | 2 +-
.../peertopeer/PeerToPeerViewModel.kt | 5 +--
.../fragment/peertopeer/di/PeerModule.kt | 2 +-
.../receipentflow/QRCodeFragment.kt | 18 +++-----
.../RecipientVerificationFragment.kt | 1 +
.../receipentflow/ShowDeviceInfoFragment.kt | 1 +
.../SenderManualConnectionFragment.kt | 2 +
.../senderflow/SenderVerificationFragment.kt | 4 ++
10 files changed, 59 insertions(+), 21 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
rename mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/{ => managers}/PeerToPeerManager.kt (85%)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 5b85fdcf6..f5950a808 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -16,16 +16,14 @@ import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
-import io.ktor.server.plugins.callloging.CallLogging
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import kotlinx.coroutines.launch
-import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
new file mode 100644
index 000000000..046ac8e5a
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
@@ -0,0 +1,41 @@
+package org.horizontal.tella.mobile.data.peertopeer.managers
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerServer
+import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
+import java.security.KeyPair
+import java.security.cert.X509Certificate
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class PeerServerStarterManager @Inject constructor(
+ private val peerToPeerManager: PeerToPeerManager
+) {
+ private var server: TellaPeerToPeerServer? = null
+
+ fun startServer(ip: String, keyPair: KeyPair, cert: X509Certificate, config: KeyStoreConfig) {
+ if (server == null) {
+ server = TellaPeerToPeerServer(
+ ip = ip,
+ keyPair = keyPair,
+ certificate = cert,
+ keyStoreConfig = config,
+ peerToPeerManager = peerToPeerManager
+ )
+ server?.start()
+ }
+ }
+
+ //TODO: AHLEM CHECK WHERE WE WANT TO STOP THE SERVER
+ fun stopServer() {
+ CoroutineScope(Dispatchers.IO).launch {
+ server?.stop()
+ server = null
+ }
+ }
+
+ fun isRunning(): Boolean = server != null
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerToPeerManager.kt
similarity index 85%
rename from mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerManager.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerToPeerManager.kt
index b38314cb8..f0ccbc4ae 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerToPeerManager.kt
@@ -1,4 +1,4 @@
-package org.horizontal.tella.mobile.data.peertopeer
+package org.horizontal.tella.mobile.data.peertopeer.managers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 98c86766e..f4e95965e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -21,17 +21,14 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
-import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
-import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.NetworkInfo
import timber.log.Timber
import java.net.Inet4Address
import java.net.NetworkInterface
-import java.security.MessageDigest
-import java.util.UUID
import javax.inject.Inject
@HiltViewModel
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
index f47f324c3..5fb51fbf1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
@@ -4,7 +4,7 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
-import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import javax.inject.Singleton
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 131e0b7b4..2c4b98ab9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -4,7 +4,6 @@ import android.graphics.Bitmap
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
import com.google.zxing.BarcodeFormat
import com.google.zxing.WriterException
@@ -12,9 +11,9 @@ import com.journeyapps.barcodescanner.BarcodeEncoder
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.certificate.CertificateGenerator
import org.horizontal.tella.mobile.certificate.CertificateUtils
-import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
-import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerServer
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.data.peertopeer.port
import org.horizontal.tella.mobile.databinding.FragmentQrCodeBinding
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
@@ -30,6 +29,8 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
private var server: TellaServer? = null
private var payload: PeerConnectionPayload? = null
private lateinit var qrPayload: String
+ @Inject
+ lateinit var peerServerStarterManager: PeerServerStarterManager
@Inject
lateinit var peerToPeerManager: PeerToPeerManager
@@ -60,14 +61,8 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val (keyPair, certificate) = CertificateGenerator.generateCertificate(ipAddress = ip)
val config = KeyStoreConfig()
- server = TellaPeerToPeerServer(
- ip = ip,
- keyPair = keyPair,
- certificate = certificate,
- keyStoreConfig = config,
- peerToPeerManager = peerToPeerManager
- )
- server?.start()
+ peerServerStarterManager.startServer(ip, keyPair, certificate, config)
+
val certHash = CertificateUtils.getPublicKeyHash(certificate)
val pin = "111111"
@@ -128,5 +123,4 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
}
}
-
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 4c778965e..1ba6d6cdd 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -22,6 +22,7 @@ class RecipientVerificationFragment :
}
initListeners()
initView()
+ initObservers()
}
private fun initView() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 6f964d8ba..7e3e7c416 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -37,6 +37,7 @@ class ShowDeviceInfoFragment :
private fun initListeners() {
binding.backBtn.setOnClickListener { back() }
+ binding.toolbar.backClickListener = { nav().popBackStack() }
}
private fun initObservers() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index b6ab840a0..fe7c609c3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -68,6 +68,8 @@ class SenderManualConnectionFragment :
if (enabled) android.R.color.white else android.R.color.darker_gray
)
)
+ binding.toolbar.backClickListener = { nav().popBackStack() }
+ binding.backBtn.setOnClickListener { nav().popBackStack() }
binding.nextBtn.setOnClickListener {
val ip = binding.connectCode.text.toString()
val port = binding.port.text.toString()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 955d23e60..704ef46e7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -46,6 +46,10 @@ class SenderVerificationFragment :
pin = peerConnectionInfo.pin.toString()
)
}
+
+ binding.discardBtn.setOnClickListener {
+
+ }
}
private fun initObservers() {
From c19c68ab2854aefcba3875f238cdb6f1f07366af Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 4 Jun 2025 11:43:40 +0100
Subject: [PATCH 021/153] handle the accept reject flow
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 19 ++++++---
.../fragment/peertopeer/PeerEventManager.kt | 22 ++++++----
.../peertopeer/PeerToPeerViewModel.kt | 25 ++++++------
.../fragment/peertopeer/WaitingFragment.kt | 17 ++++++++
.../receipentflow/RecipientSuccessFragment.kt | 40 ++++++++++++++++++-
.../res/layout/fragment_recipient_success.xml | 2 +-
mobile/src/main/res/values/strings.xml | 2 +
7 files changed, 101 insertions(+), 26 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index f5950a808..272f4bb7f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -131,11 +131,20 @@ class TellaPeerToPeerServer(
call.respond(HttpStatusCode.BadRequest, "Missing required fields")
return@post
}
- val transmissionId = UUID.randomUUID().toString()
- call.respond(
- HttpStatusCode.OK,
- PeerPrepareUploadResponse(transmissionId)
- )
+
+ val accepted = PeerEventManager.emitPrepareUploadRequest(request)
+
+ if (accepted) {
+ val transmissionId = UUID.randomUUID().toString()
+ call.respond(HttpStatusCode.OK, PeerPrepareUploadResponse(transmissionId))
+ } else {
+ call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
+ }
+// val transmissionId = UUID.randomUUID().toString()
+// call.respond(
+// HttpStatusCode.OK,
+// PeerPrepareUploadResponse(transmissionId)
+// )
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
index ae74c10cc..8185f82a8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
@@ -3,7 +3,9 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.ApplicationCall
import io.ktor.server.response.respond
+import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
/**
@@ -22,13 +24,19 @@ object PeerEventManager {
// we can add emitRegistrationFailure or other event types if needed
- val prepareUploadEvents =
- MutableSharedFlow Unit>>(replay = 0)
+ private val _prepareUploadEvents = MutableSharedFlow(replay = 1)
+ val prepareUploadEvents = _prepareUploadEvents.asSharedFlow()
- suspend fun emitPrepareUploadRequest(
- request: PrepareUploadRequest,
- callback: (Boolean) -> Unit
- ) {
- prepareUploadEvents.emit(request to callback)
+ private val decisionMap = mutableMapOf>()
+
+ suspend fun emitPrepareUploadRequest(request: PrepareUploadRequest): Boolean {
+ val deferred = CompletableDeferred()
+ decisionMap[request.sessionId] = deferred
+ _prepareUploadEvents.emit(request)
+ return deferred.await() // Wait for UI decision
+ }
+
+ fun resolveUserDecision(sessionId: String, accepted: Boolean) {
+ decisionMap.remove(sessionId)?.complete(accepted)
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index f4e95965e..245d0f42b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -49,21 +49,19 @@ class PeerToPeerViewModel @Inject constructor(
val getHashError: LiveData get() = _getHashError
private val _sessionInfo = MutableStateFlow(null)
val sessionInfo: StateFlow = _sessionInfo
+ val clientHash = peerToPeerManager.clientConnected
private val _registrationServerSuccess = MutableLiveData()
val registrationServerSuccess: LiveData = _registrationServerSuccess
- private val _incomingUploadRequest = MutableLiveData()
- val incomingUploadRequest: LiveData = _incomingUploadRequest
-
- val clientHash = peerToPeerManager.clientConnected
+ private val _incomingPrepareRequest = MutableLiveData()
+ val incomingPrepareRequest: LiveData = _incomingPrepareRequest
-
-// init {
-// viewModelScope.launch {
-// PeerEventManager.incomingUploadRequests.collect { request ->
-// _incomingUploadRequest.postValue(request)
-// }
-// }
-// }
+ init {
+ viewModelScope.launch {
+ PeerEventManager.prepareUploadEvents.collect { request ->
+ _incomingPrepareRequest.postValue(request)
+ }
+ }
+ }
init {
viewModelScope.launch {
@@ -75,6 +73,9 @@ class PeerToPeerViewModel @Inject constructor(
fun resetRegistrationState() {
_registrationServerSuccess.postValue(false)
}
+ fun confirmPrepareUpload(sessionId: String, accepted: Boolean) {
+ PeerEventManager.resolveUserDecision(sessionId, accepted)
+ }
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("MissingPermission", "DiscouragedPrivateApi")
fun fetchCurrentNetworkInfo() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
index 6a8f91469..879e81fe1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -2,6 +2,8 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import android.os.Bundle
import android.view.View
+import android.widget.Toast
+import androidx.fragment.app.activityViewModels
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
@@ -10,6 +12,7 @@ import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
* Created by wafa on 3/6/2025.
*/
class WaitingFragment : BaseBindingFragment(FragmentWaitingBinding::inflate){
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -25,6 +28,20 @@ class WaitingFragment : BaseBindingFragment(FragmentWait
binding.toolbar.setToolbarTitle(getString(R.string.send_files))
binding.waitingText.text = "Waiting for the recipient to accept files"
}
+
+ viewModel.incomingPrepareRequest.observe(viewLifecycleOwner) { request ->
+ val fileCount = request.files.size
+ bundle.putInt("fileCount", fileCount)
+ bundle.putString("sessionId", request.sessionId)
+ navManager().navigateFromWaitingFragmentToRecipientSuccessFragment()
+ }
+
+ childFragmentManager.setFragmentResultListener("prepare_upload_result", viewLifecycleOwner) { _, result ->
+ val wasRejected = result.getBoolean("rejected", false)
+ if (wasRejected) {
+ Toast.makeText(requireContext(), "Sender's files rejected.", Toast.LENGTH_LONG).show()
+ }
+ }
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 73731a4e8..8cdc5f5c7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -2,23 +2,61 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
+import android.widget.Toast
+import androidx.core.os.bundleOf
+import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.setFragmentResult
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
-import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
/**
* Created by wafa on 3/6/2025.
*/
class RecipientSuccessFragment : BaseBindingFragment(FragmentRecipientSuccessBinding::inflate){
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ initView()
+ }
+ private fun initView() {
+ val fileCount = arguments?.getInt("fileCount") ?: 0
+ val sessionId = arguments?.getString("sessionId").orEmpty()
+
+ with(binding) {
+ // Set the dynamic message
+ waitingText.text = getString(R.string.prepare_upload_message, fileCount)
+
+ // Handle Accept/Reject buttons
+ acceptBtn.setOnClickListener {
+ onAcceptFilesSelected()
+ viewModel.confirmPrepareUpload(sessionId, true)
+ }
+
+ rejectBtn.setOnClickListener {
+ onRejectFilesSelected()
+ viewModel.confirmPrepareUpload(sessionId, false)
+ // Set result to notify previous fragment
+ setFragmentResult("prepare_upload_result", bundleOf("rejected" to true))
+ nav().popBackStack()
+ }
+ }
+ }
+
+ private fun onAcceptFilesSelected() {
+ binding.acceptBtn.isChecked = true
+ binding.rejectBtn.isChecked = false
+ }
+ private fun onRejectFilesSelected() {
+ binding.rejectBtn.isChecked = true
+ binding.acceptBtn.isChecked = false
}
}
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/fragment_recipient_success.xml b/mobile/src/main/res/layout/fragment_recipient_success.xml
index 2024ba579..e8549b235 100644
--- a/mobile/src/main/res/layout/fragment_recipient_success.xml
+++ b/mobile/src/main/res/layout/fragment_recipient_success.xml
@@ -29,7 +29,7 @@
style="@style/Tella_Main_White_TextExtraLargeBold"
android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_large_margin"
- android:text="The sender is trying to send you 6 files"
+ android:text="@string/prepare_upload_message"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index f157f071e..2a290942b 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1041,4 +1041,6 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
If the sequence on your device does not match the sequence on the recipient’s device, the connection may not be secure and should be discarded.
Discard and start over
Waiting for the sender to share files
+ The sender is trying to send you %1$d files
+
From 0bc3a8ae5e721bf56c18d7dbb04d280f2effa29a Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 4 Jun 2025 11:53:56 +0100
Subject: [PATCH 022/153] handle discard and go back to first destination
---
.../tella/mobile/util/NavigationManager.kt | 16 ++++++++++++++++
.../RecipientVerificationFragment.kt | 18 +++++++-----------
.../senderflow/SenderVerificationFragment.kt | 7 ++++++-
3 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index ba8d69358..dbd59de0c 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -1,6 +1,7 @@
package org.horizontal.tella.mobile.util
import android.os.Bundle
+import androidx.navigation.navOptions
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.views.fragment.reports.di.NavControllerProvider
@@ -199,6 +200,7 @@ class NavigationManager(
fun navigateFromDeviceInfoScreenTRecipientVerificationScreen(){
navigateToWithBundle(R.id.action_deviceInfoScreen_to_recipientVerificationScreen)
}
+
fun navigateFromQrCodeScreenToWaitingFragment() {
navigateToWithBundle(R.id.action_qrCodeScreen_to_waitingFragment)
}
@@ -210,10 +212,24 @@ class NavigationManager(
fun navigateConnectManuallyVerificationFragmentToprepareUploadFragment(){
navigateToWithBundle(R.id.action_connectManuallyVerificationFragment_to_prepareUploadFragment)
}
+
fun navigateFromRecipientVerificationScreenToWaitingFragment(){
navigateToWithBundle(R.id.action_recipientVerificationScreen_to_waitingFragment)
}
+
fun navigateFromWaitingFragmentToRecipientSuccessFragment(){
navigateToWithBundle(R.id.action_waitingFragment_to_recipientSuccessFragment)
}
+
+ fun navigateBackToStartNearBySharingFragmentAndClearBackStack() {
+ navControllerProvider.navController.navigate(
+ R.id.startNearBySharingFragment,
+ bundle,
+ navOptions {
+ popUpTo(R.id.startNearBySharingFragment) {
+ inclusive = true
+ }
+ }
+ )
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 1ba6d6cdd..0c838617b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -22,7 +22,13 @@ class RecipientVerificationFragment :
}
initListeners()
initView()
- initObservers()
+ viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
+ } else {
+ }
+ }
}
private fun initView() {
@@ -38,14 +44,4 @@ class RecipientVerificationFragment :
}
}
-
- private fun initObservers() {
- viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
- if (success) {
- bundle.putBoolean("isSender", false)
- navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
- } else {
- }
- }
- }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 704ef46e7..308889bf5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -5,16 +5,21 @@ import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import javax.inject.Inject
class SenderVerificationFragment :
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
private lateinit var peerConnectionInfo: PeerConnectionInfo
+ @Inject
+ lateinit var peerServerStarterManager: PeerServerStarterManager
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initListeners()
@@ -48,7 +53,7 @@ class SenderVerificationFragment :
}
binding.discardBtn.setOnClickListener {
-
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
}
From f6740c312de254d12bbaf088455eb2de25f84d03 Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 4 Jun 2025 13:49:45 +0100
Subject: [PATCH 023/153] wip flow prepare load
---
.../fragment/peertopeer/SenderViewModel.kt | 17 ++++++++--
.../fragment/peertopeer/WaitingFragment.kt | 24 +++++++++++---
.../receipentflow/RecipientSuccessFragment.kt | 9 +++---
.../senderflow/PrepareUploadFragment.kt | 32 ++++++++++++++++++-
.../res/layout/fragment_recipient_success.xml | 4 +--
.../src/main/res/layout/fragment_waiting.xml | 9 ++++++
mobile/src/main/res/values/strings.xml | 5 +++
7 files changed, 86 insertions(+), 14 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 8b399337e..693349d4e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -12,6 +12,7 @@ import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.launch
+import org.apache.commons.httpclient.HttpException
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
@@ -28,6 +29,8 @@ class SenderViewModel @Inject constructor(
) : ViewModel() {
private val _prepareResults = MutableLiveData()
val prepareResults: LiveData = _prepareResults
+ private val _prepareRejected = MutableLiveData()
+ val prepareRejected: LiveData = _prepareRejected
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
@@ -82,8 +85,18 @@ class SenderViewModel @Inject constructor(
Timber.d("Success: transmissionId = $transmissionId")
_prepareResults.postValue(PeerPrepareUploadResponse(transmissionId))
}.onFailure { error ->
- Timber.e(error, "Failed to prepare upload for ${files.size} files")
- // Optionally post a failure state to LiveData if needed
+ if (error is retrofit2.HttpException) {
+ val code = error.code()
+ if (code == 403) {
+ // Rejected by the receiver
+ _prepareRejected.postValue(true)
+ } else {
+ Timber.e("HTTP error: ${error.code()} - ${error.message()}")
+ }
+ } else {
+ Timber.e(error, "Unexpected error during prepare upload")
+ }
+
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
index 879e81fe1..c744c5992 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -3,16 +3,21 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import android.os.Bundle
import android.view.View
import android.widget.Toast
+import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.setFragmentResult
+import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
*/
class WaitingFragment : BaseBindingFragment(FragmentWaitingBinding::inflate){
private val viewModel: PeerToPeerViewModel by activityViewModels()
+ private val viewModelSender: SenderViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -22,11 +27,11 @@ class WaitingFragment : BaseBindingFragment(FragmentWait
val isSender = arguments?.getBoolean("isSender") ?: false
if (!isSender) {
- binding.toolbar.setToolbarTitle(getString(R.string.receive_files))
+ binding.toolbar.setStartTextTitle(getString(R.string.receive_files))
binding.waitingText.text = getString(R.string.waiting_for_the_sender_to_share_files)
} else {
- binding.toolbar.setToolbarTitle(getString(R.string.send_files))
- binding.waitingText.text = "Waiting for the recipient to accept files"
+ binding.toolbar.setStartTextTitle(getString(R.string.send_files))
+ binding.waitingText.text = getString(R.string.waiting_for_the_recipient_to_accept_files)
}
viewModel.incomingPrepareRequest.observe(viewLifecycleOwner) { request ->
@@ -36,10 +41,19 @@ class WaitingFragment : BaseBindingFragment(FragmentWait
navManager().navigateFromWaitingFragmentToRecipientSuccessFragment()
}
- childFragmentManager.setFragmentResultListener("prepare_upload_result", viewLifecycleOwner) { _, result ->
+ viewModelSender.prepareRejected.observe(viewLifecycleOwner) { wasRejected ->
+ if (wasRejected) {
+ parentFragmentManager.setFragmentResult("prepare_upload_result", bundleOf("rejected" to true))
+ findNavController().popBackStack()
+ }
+ }
+ parentFragmentManager.setFragmentResultListener("prepare_upload_result", viewLifecycleOwner) { _, result ->
val wasRejected = result.getBoolean("rejected", false)
if (wasRejected) {
- Toast.makeText(requireContext(), "Sender's files rejected.", Toast.LENGTH_LONG).show()
+ DialogUtils.showBottomMessage(
+ baseActivity, "Sender's files rejected.",
+ true
+ )
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 8cdc5f5c7..098bd6a38 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -6,6 +6,7 @@ import android.widget.Toast
import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.setFragmentResult
+import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
@@ -34,16 +35,16 @@ class RecipientSuccessFragment : BaseBindingFragment
+ val wasRejected = result.getBoolean("rejected", false)
+ if (wasRejected) {
+ showTooltip(
+ binding.root,
+ "Recipient rejected the files.",
+ Gravity.TOP
+ )
+ }
+ }
viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
val id = response.transmissionId
// navigate to next screen
}
+
+ binding.toolbar.backClickListener = { BottomSheetUtils.showConfirmSheet(
+ baseActivity.supportFragmentManager,
+ getString((R.string.exit_nearby_sharing)),
+ getString(R.string.your_progress_will_be_lost),
+ getString(R.string.action_exit),
+ getString(R.string.action_cancel),
+ object : BottomSheetUtils.ActionConfirmed {
+ override fun accept(isConfirmed: Boolean) {
+ if (isConfirmed) {
+ findNavController().popBackStack()
+ }
+ }
+ }
+ )
+ }
highLightButtonsInit()
checkIsNewDraftEntry()
}
diff --git a/mobile/src/main/res/layout/fragment_recipient_success.xml b/mobile/src/main/res/layout/fragment_recipient_success.xml
index e8549b235..ddd7d88d5 100644
--- a/mobile/src/main/res/layout/fragment_recipient_success.xml
+++ b/mobile/src/main/res/layout/fragment_recipient_success.xml
@@ -66,7 +66,7 @@
android:layout_marginTop="50dp"
android:background="@drawable/bg_round_orange_btn"
app:text_color="@color/btn_dark_letter"
- app:text="ACCEPT"
+ app:text="@string/accept"
app:check_state="false"
app:layout_constraintBottom_toTopOf="@+id/reject_btn"
app:layout_constraintEnd_toEndOf="parent"
@@ -81,7 +81,7 @@
android:layout_marginHorizontal="@dimen/activity_horizontal_large_margin"
android:layout_marginTop="10dp"
android:gravity="center"
- app:text="REJECT"
+ app:text="@string/reject"
app:layout_constraintTop_toBottomOf="@+id/accept_btn" />
diff --git a/mobile/src/main/res/layout/fragment_waiting.xml b/mobile/src/main/res/layout/fragment_waiting.xml
index 43f87cad7..8ec3ec9a4 100644
--- a/mobile/src/main/res/layout/fragment_waiting.xml
+++ b/mobile/src/main/res/layout/fragment_waiting.xml
@@ -48,6 +48,15 @@
app:layout_constraintTop_toBottomOf="@+id/waiting_text"
app:layout_constraintVertical_chainStyle="packed" />
+
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index 2a290942b..5263de3ff 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1042,5 +1042,10 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Discard and start over
Waiting for the sender to share files
The sender is trying to send you %1$d files
+ Waiting for the recipient to accept files
+ ACCEPT
+ REJECT
+ Exit nearby sharing?
+ Your progress will be lost.
From f226f894b229be608f39a19715bc0a9e0787763b Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 4 Jun 2025 13:51:56 +0100
Subject: [PATCH 024/153] Wip finish manual connection
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 1 -
.../peertopeer/PeerToPeerViewModel.kt | 3 +-
.../receipentflow/QRCodeFragment.kt | 6 ++--
.../RecipientVerificationFragment.kt | 28 +++++++++++++++++--
.../receipentflow/ShowDeviceInfoFragment.kt | 5 +++-
.../senderflow/SenderVerificationFragment.kt | 12 ++++++++
.../layout/connect_manually_verification.xml | 2 +-
7 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 272f4bb7f..d92cbea5b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -63,7 +63,6 @@ class TellaPeerToPeerServer(
}
engine = embeddedServer(Netty, environment = applicationEngineEnvironment {
- var firstConnectionReceived = false
sslConnector(
keyStore = keyStore,
keyAlias = keyStoreConfig.alias,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 245d0f42b..d72109a8d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -61,15 +61,14 @@ class PeerToPeerViewModel @Inject constructor(
_incomingPrepareRequest.postValue(request)
}
}
- }
- init {
viewModelScope.launch {
PeerEventManager.registrationEvents.collect { success ->
_registrationServerSuccess.postValue(success)
}
}
}
+
fun resetRegistrationState() {
_registrationServerSuccess.postValue(false)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 2c4b98ab9..ff2018a40 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -11,12 +11,12 @@ import com.journeyapps.barcodescanner.BarcodeEncoder
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.certificate.CertificateGenerator
import org.horizontal.tella.mobile.certificate.CertificateUtils
-import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
-import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.port
import org.horizontal.tella.mobile.databinding.FragmentQrCodeBinding
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
+import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
@@ -65,7 +65,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val certHash = CertificateUtils.getPublicKeyHash(certificate)
- val pin = "111111"
+ val pin = (100000..999999).random().toString()
val port = port
payload = PeerConnectionPayload(
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 0c838617b..abe893111 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -5,16 +5,22 @@ import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import javax.inject.Inject
class RecipientVerificationFragment :
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
private var payload: PeerConnectionPayload? = null
+ @Inject
+ lateinit var peerServerStarterManager: PeerServerStarterManager
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
arguments?.getString("payload")?.let { payloadJson ->
@@ -24,9 +30,11 @@ class RecipientVerificationFragment :
initView()
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- bundle.putBoolean("isSender", false)
- navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
- } else {
+ binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
+ binding.confirmAndConnectBtn.setOnClickListener {
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
+ }
}
}
}
@@ -41,7 +49,21 @@ class RecipientVerificationFragment :
private fun initListeners() {
binding.confirmAndConnectBtn.setOnClickListener {
+ binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
+
+ }
+ binding.toolbar.backClickListener = {
+ peerServerStarterManager.stopServer()
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
+
+ binding.discardBtn.setOnClickListener {
+ peerServerStarterManager.stopServer()
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
}
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 7e3e7c416..e63668469 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -55,10 +55,13 @@ class ShowDeviceInfoFragment :
}
}
- viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
+ viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
+ // Navigate to the next screen
bundle.putBoolean("isSender", false)
navManager().navigateFromQrCodeScreenToWaitingFragment()
+ // reset the LiveData state if we want to consume event once
+ viewModel.resetRegistrationState()
} else {
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 308889bf5..611d870d6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -28,6 +28,7 @@ class SenderVerificationFragment :
}
private fun initView() {
+ binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
binding.titleDescTextView.text = getString(R.string.make_sure_sequence_matches_recipient)
binding.warningTextView.text = getString(R.string.sequence_mismatch_warning_recipient)
@@ -58,6 +59,17 @@ class SenderVerificationFragment :
}
private fun initObservers() {
+
+ viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
+ if (success) {
+ // Navigate to the next screen
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingFragment()
+ // reset the LiveData state if we want to consume event once
+ viewModel.resetRegistrationState()
+ } else {
+ }
+ }
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
navManager().navigateConnectManuallyVerificationFragmentToprepareUploadFragment()
diff --git a/mobile/src/main/res/layout/connect_manually_verification.xml b/mobile/src/main/res/layout/connect_manually_verification.xml
index 022c99308..67e6c4ffb 100644
--- a/mobile/src/main/res/layout/connect_manually_verification.xml
+++ b/mobile/src/main/res/layout/connect_manually_verification.xml
@@ -95,7 +95,7 @@
android:layout_height="54dp"
android:layout_marginTop="@dimen/activity_horizontal_large_margin"
android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
- android:background="@drawable/bg_round_orange_btn"
+ android:background="@drawable/bg_round_orange16_btn"
app:text_color="@color/btn_dark_letter"
app:check_state="false"
app:layout_constraintTop_toBottomOf="@id/warningTextView"
From 4d3a778ae01de6e013e7871caa7e372c19810483 Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 4 Jun 2025 13:56:54 +0100
Subject: [PATCH 025/153] wip add success message
---
.../senderflow/PrepareUploadFragment.kt | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 98a04812e..3f46e2277 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -95,15 +95,26 @@ class PrepareUploadFragment :
parentFragmentManager.setFragmentResultListener("prepare_upload_result", viewLifecycleOwner) { _, result ->
val wasRejected = result.getBoolean("rejected", false)
if (wasRejected) {
- showTooltip(
- binding.root,
- "Recipient rejected the files.",
- Gravity.TOP
+// showTooltip(
+// binding.root,
+// "Recipient rejected the files.",
+// Gravity.TOP
+// )
+ DialogUtils.showBottomMessage(
+ baseActivity, "Recipient rejected the files.",
+ true
)
+
}
}
viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
val id = response.transmissionId
+ DialogUtils.showBottomMessage(
+ baseActivity,
+ "The receiver accepted the files transfer ",
+ false,
+ 3000
+ )
// navigate to next screen
}
From 8abd68a72ac950f0bd826c552df4a79187fc44aa Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 4 Jun 2025 13:59:45 +0100
Subject: [PATCH 026/153] WIP on feat/stable_peer_to_peer
add back button
---
.../fragment/peertopeer/WaitingFragment.kt | 18 +++++++++++++-----
.../senderflow/PrepareUploadFragment.kt | 3 +++
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
index c744c5992..f4d19a541 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -2,10 +2,8 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import android.os.Bundle
import android.view.View
-import android.widget.Toast
import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
-import androidx.fragment.app.setFragmentResult
import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
@@ -15,7 +13,8 @@ import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
*/
-class WaitingFragment : BaseBindingFragment(FragmentWaitingBinding::inflate){
+class WaitingFragment :
+ BaseBindingFragment(FragmentWaitingBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
private val viewModelSender: SenderViewModel by activityViewModels()
@@ -26,6 +25,9 @@ class WaitingFragment : BaseBindingFragment(FragmentWait
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val isSender = arguments?.getBoolean("isSender") ?: false
+ binding.toolbar.backClickListener = {
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
if (!isSender) {
binding.toolbar.setStartTextTitle(getString(R.string.receive_files))
binding.waitingText.text = getString(R.string.waiting_for_the_sender_to_share_files)
@@ -43,11 +45,17 @@ class WaitingFragment : BaseBindingFragment(FragmentWait
viewModelSender.prepareRejected.observe(viewLifecycleOwner) { wasRejected ->
if (wasRejected) {
- parentFragmentManager.setFragmentResult("prepare_upload_result", bundleOf("rejected" to true))
+ parentFragmentManager.setFragmentResult(
+ "prepare_upload_result",
+ bundleOf("rejected" to true)
+ )
findNavController().popBackStack()
}
}
- parentFragmentManager.setFragmentResultListener("prepare_upload_result", viewLifecycleOwner) { _, result ->
+ parentFragmentManager.setFragmentResultListener(
+ "prepare_upload_result",
+ viewLifecycleOwner
+ ) { _, result ->
val wasRejected = result.getBoolean("rejected", false)
if (wasRejected) {
DialogUtils.showBottomMessage(
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 3f46e2277..6b9ffb230 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -71,6 +71,9 @@ class PrepareUploadFragment :
}
private fun initView() {
+ binding.toolbar.backClickListener = {
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
gridLayoutManager = GridLayoutManager(context, 3)
binding.filesRecyclerView.apply {
layoutManager = gridLayoutManager
From a692d50b995711e0f1c337df018d434e4f024aa2 Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 4 Jun 2025 14:14:50 +0100
Subject: [PATCH 027/153] add message of success
---
.../peertopeer/receipentflow/RecipientSuccessFragment.kt | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 098bd6a38..69cdc886c 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -11,6 +11,7 @@ import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
@@ -37,6 +38,12 @@ class RecipientSuccessFragment : BaseBindingFragment
Date: Tue, 10 Jun 2025 10:58:53 +0100
Subject: [PATCH 028/153] add success string
---
mobile/src/main/res/layout/show_device_info_layout.xml | 2 +-
mobile/src/main/res/values/strings.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mobile/src/main/res/layout/show_device_info_layout.xml b/mobile/src/main/res/layout/show_device_info_layout.xml
index 3cc3442e0..9007ac211 100644
--- a/mobile/src/main/res/layout/show_device_info_layout.xml
+++ b/mobile/src/main/res/layout/show_device_info_layout.xml
@@ -73,7 +73,7 @@
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/titleDescTextView"
- app:leftText="@string/connect_code" />
+ app:leftText="@string/ip_address" />
REJECT
Exit nearby sharing?
Your progress will be lost.
-
+ IP address
From d311889ecbcd20913709d15e7fa7511f9afb234f Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 10 Jun 2025 22:59:17 +0100
Subject: [PATCH 029/153] change the connectCode to ipAdress
---
.../tella/mobile/domain/peertopeer/PeerConnectionPayload.kt | 4 ++--
.../views/fragment/peertopeer/receipentflow/QRCodeFragment.kt | 2 +-
.../peertopeer/receipentflow/ShowDeviceInfoFragment.kt | 4 ++--
.../fragment/peertopeer/senderflow/ScanQrCodeFragment.kt | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
index 7a28595c5..81bb98411 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
@@ -3,8 +3,8 @@ package org.horizontal.tella.mobile.domain.peertopeer
import com.google.gson.annotations.SerializedName
data class PeerConnectionPayload(
- @SerializedName("connect_code")
- val connectCode: String,
+ @SerializedName("ip_address")
+ val ipAdress: String,
@SerializedName("port")
val port: Int,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index ff2018a40..41fa4c4fc 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -69,7 +69,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val port = port
payload = PeerConnectionPayload(
- connectCode = ip,
+ ipAdress = ip,
port = port,
certificateHash = certHash,
pin = pin
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index e63668469..5994cd7bf 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -30,7 +30,7 @@ class ShowDeviceInfoFragment :
}
private fun initView() {
- binding.connectCode.setRightText(payload?.connectCode)
+ binding.connectCode.setRightText(payload?.ipAdress)
binding.pin.setRightText(payload?.pin)
binding.port.setRightText(payload?.port.toString())
}
@@ -45,7 +45,7 @@ class ShowDeviceInfoFragment :
viewModel.clientHash.collect { hash ->
viewModel.setPeerSessionInfo(
PeerConnectionInfo(
- ip = payload?.connectCode.toString(),
+ ip = payload?.ipAdress.toString(),
port = payload?.port.toString(),
pin = payload?.pin?.toInt()!!,
hash = hash
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 99e265911..8e06174a1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -61,7 +61,7 @@ class ScanQrCodeFragment :
val payload = Gson().fromJson(qrContent, PeerConnectionPayload::class.java)
viewModel.startRegistration(
- ip = payload.connectCode,
+ ip = payload.ipAdress,
port = payload.port.toString(),
hash = payload.certificateHash,
pin = payload.pin
From 55911eabec08df2d1df8533ff5bdc9777669d871 Mon Sep 17 00:00:00 2001
From: wafa
Date: Thu, 19 Jun 2025 13:18:23 +0100
Subject: [PATCH 030/153] wip reject flow
---
.../peertopeer/PeerToPeerViewModel.kt | 10 ++--
.../fragment/peertopeer/WaitingFragment.kt | 53 ++++++++++++-------
.../receipentflow/RecipientSuccessFragment.kt | 19 +++----
3 files changed, 47 insertions(+), 35 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index d72109a8d..d21b04f0a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -38,6 +38,7 @@ class PeerToPeerViewModel @Inject constructor(
private val peerToPeerManager: PeerToPeerManager
) : ViewModel() {
+ var hasNavigatedToSuccessFragment = false
private val _networkInfo = MutableLiveData()
val networkInfo: LiveData = _networkInfo
var currentNetworkInfo: NetworkInfo? = null
@@ -52,8 +53,8 @@ class PeerToPeerViewModel @Inject constructor(
val clientHash = peerToPeerManager.clientConnected
private val _registrationServerSuccess = MutableLiveData()
val registrationServerSuccess: LiveData = _registrationServerSuccess
- private val _incomingPrepareRequest = MutableLiveData()
- val incomingPrepareRequest: LiveData = _incomingPrepareRequest
+ private val _incomingPrepareRequest = MutableLiveData()
+ val incomingPrepareRequest: MutableLiveData = _incomingPrepareRequest
init {
viewModelScope.launch {
@@ -219,7 +220,10 @@ class PeerToPeerViewModel @Inject constructor(
}
}
-
+ fun clearPrepareRequest() {
+ _incomingPrepareRequest.value = null
+ hasNavigatedToSuccessFragment = false
+ }
fun setPeerSessionInfo(info: PeerConnectionInfo) {
_sessionInfo.value = info
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
index f4d19a541..1ad4dd312 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -18,10 +18,6 @@ class WaitingFragment :
private val viewModel: PeerToPeerViewModel by activityViewModels()
private val viewModelSender: SenderViewModel by activityViewModels()
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- }
-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val isSender = arguments?.getBoolean("isSender") ?: false
@@ -37,10 +33,14 @@ class WaitingFragment :
}
viewModel.incomingPrepareRequest.observe(viewLifecycleOwner) { request ->
- val fileCount = request.files.size
- bundle.putInt("fileCount", fileCount)
- bundle.putString("sessionId", request.sessionId)
- navManager().navigateFromWaitingFragmentToRecipientSuccessFragment()
+ if (request != null && !viewModel.hasNavigatedToSuccessFragment) {
+ viewModel.hasNavigatedToSuccessFragment = true
+
+ val fileCount = request.files.size
+ bundle.putInt("fileCount", fileCount)
+ bundle.putString("sessionId", request.sessionId)
+ navManager().navigateFromWaitingFragmentToRecipientSuccessFragment()
+ }
}
viewModelSender.prepareRejected.observe(viewLifecycleOwner) { wasRejected ->
@@ -52,18 +52,33 @@ class WaitingFragment :
findNavController().popBackStack()
}
}
- parentFragmentManager.setFragmentResultListener(
- "prepare_upload_result",
- viewLifecycleOwner
- ) { _, result ->
- val wasRejected = result.getBoolean("rejected", false)
- if (wasRejected) {
- DialogUtils.showBottomMessage(
- baseActivity, "Sender's files rejected.",
- true
- )
+
+ val navBackStackEntry = findNavController().currentBackStackEntry
+ navBackStackEntry?.savedStateHandle?.getLiveData("prepare_upload_result")
+ ?.observe(viewLifecycleOwner) { wasRejected ->
+ if (wasRejected) {
+ DialogUtils.showBottomMessage(
+ baseActivity, "Sender's files rejected.",
+ true
+ )
+ }
}
- }
}
+ // parentFragmentManager.setFragmentResultListener(
+// "prepare_upload_result",
+// viewLifecycleOwner
+// ) { _, result ->
+// val wasRejected = result.getBoolean("rejected", false)
+// if (wasRejected) {
+// DialogUtils.showBottomMessage(
+// baseActivity, "Sender's files rejected.",
+// true
+// )
+// }
+// }
+ override fun onStop() {
+ super.onStop()
+ viewModel.clearPrepareRequest()
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 69cdc886c..53bbb186f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -47,24 +47,17 @@ class RecipientSuccessFragment : BaseBindingFragment
Date: Fri, 20 Jun 2025 11:36:48 +0100
Subject: [PATCH 031/153] wip reject flow in the sender and recipient
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 18 ++++++-------
.../fragment/peertopeer/SenderViewModel.kt | 17 +++----------
.../fragment/peertopeer/WaitingFragment.kt | 23 +++++------------
.../receipentflow/RecipientSuccessFragment.kt | 2 +-
.../senderflow/PrepareUploadFragment.kt | 25 ++++++++-----------
5 files changed, 28 insertions(+), 57 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 04d03cb4b..d0682d980 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -131,17 +131,12 @@ class TellaPeerToPeerClient {
id = it.id,
fileName = it.name,
size = it.size,
- fileType = "application/octet-stream", // or detect mime type
+ fileType = "application/octet-stream",
sha256 = it.hash
)
}
- val requestPayload = PrepareUploadRequest(
- title = title,
- sessionId = sessionId,
- files = fileItems
- )
-
+ val requestPayload = PrepareUploadRequest(title, sessionId, fileItems)
val jsonPayload = Json.encodeToString(requestPayload)
val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
val client = getClientWithFingerprintValidation(expectedFingerprint)
@@ -153,11 +148,11 @@ class TellaPeerToPeerClient {
.addHeader("Content-Type", "application/json")
.build()
- client.newCall(request).execute().use { response ->
+ return@withContext client.newCall(request).execute().use { response ->
val body = response.body?.string()
if (response.isSuccessful && body != null) {
- return@use try {
+ try {
val transmissionId = JSONObject(body).getString("transmissionId")
Result.success(transmissionId)
} catch (e: Exception) {
@@ -168,21 +163,22 @@ class TellaPeerToPeerClient {
Log.e("PrepareUpload", "Server error ${response.code}: ${response.message}")
when (response.code) {
400 -> Log.e("PrepareUpload", "Bad Request – likely missing or invalid fields.")
+ 403 -> Log.e("PrepareUpload", "Forbidden – the server is refusing the request.")
409 -> Log.e("PrepareUpload", "Conflict – maybe another active session.")
500 -> Log.e("PrepareUpload", "Internal Server Error – try again later.")
else -> Log.e("PrepareUpload", "Unhandled server error code.")
}
- return@use Result.failure(Exception("Server returned error ${response.code}"))
+ Result.failure(Exception("Server returned error ${response.code}"))
}
}
- Result.failure(Exception("No response from server"))
} catch (e: Exception) {
Log.e("PrepareUpload", "Exception during upload: ${e.message}", e)
Result.failure(e)
}
}
+
suspend fun fetchServerFingerprint(ip: String, port: Int): Result = withContext(Dispatchers.IO) {
try {
val socket = SSLSocketFactory.getDefault()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 693349d4e..d370f1404 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -85,23 +85,12 @@ class SenderViewModel @Inject constructor(
Timber.d("Success: transmissionId = $transmissionId")
_prepareResults.postValue(PeerPrepareUploadResponse(transmissionId))
}.onFailure { error ->
- if (error is retrofit2.HttpException) {
- val code = error.code()
- if (code == 403) {
- // Rejected by the receiver
- _prepareRejected.postValue(true)
- } else {
- Timber.e("HTTP error: ${error.code()} - ${error.message()}")
- }
- } else {
- Timber.e(error, "Unexpected error during prepare upload")
- }
+ // if (error.message?.contains("403") == true) {
+ _prepareRejected.postValue(true)
}
+ }
}
- }
-
-
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
index 1ad4dd312..cffd1010a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
@@ -45,16 +45,16 @@ class WaitingFragment :
viewModelSender.prepareRejected.observe(viewLifecycleOwner) { wasRejected ->
if (wasRejected) {
- parentFragmentManager.setFragmentResult(
- "prepare_upload_result",
- bundleOf("rejected" to true)
- )
+ findNavController().previousBackStackEntry
+ ?.savedStateHandle
+ ?.set("prepare_upload_result", true)
+
findNavController().popBackStack()
}
}
val navBackStackEntry = findNavController().currentBackStackEntry
- navBackStackEntry?.savedStateHandle?.getLiveData("prepare_upload_result")
+ navBackStackEntry?.savedStateHandle?.getLiveData("prepare_upload")
?.observe(viewLifecycleOwner) { wasRejected ->
if (wasRejected) {
DialogUtils.showBottomMessage(
@@ -65,18 +65,7 @@ class WaitingFragment :
}
}
- // parentFragmentManager.setFragmentResultListener(
-// "prepare_upload_result",
-// viewLifecycleOwner
-// ) { _, result ->
-// val wasRejected = result.getBoolean("rejected", false)
-// if (wasRejected) {
-// DialogUtils.showBottomMessage(
-// baseActivity, "Sender's files rejected.",
-// true
-// )
-// }
-// }
+
override fun onStop() {
super.onStop()
viewModel.clearPrepareRequest()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 53bbb186f..21dcc8418 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -51,7 +51,7 @@ class RecipientSuccessFragment : BaseBindingFragment
- val wasRejected = result.getBoolean("rejected", false)
- if (wasRejected) {
-// showTooltip(
-// binding.root,
-// "Recipient rejected the files.",
-// Gravity.TOP
-// )
- DialogUtils.showBottomMessage(
- baseActivity, "Recipient rejected the files.",
- true
- )
-
+ val navBackStackEntry = findNavController().currentBackStackEntry
+ navBackStackEntry?.savedStateHandle
+ ?.getLiveData("prepare_upload_result")
+ ?.observe(viewLifecycleOwner) { wasRejected ->
+ if (wasRejected) {
+ DialogUtils.showBottomMessage(
+ baseActivity, "Recipient rejected the files.",
+ true
+ )
+ }
}
- }
+
viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
val id = response.transmissionId
DialogUtils.showBottomMessage(
From a0979109111c2751e8446d5b0128d7236787371c Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Fri, 20 Jun 2025 19:12:19 +0100
Subject: [PATCH 032/153] Fix hash problem, wip send/receive manual
---
.../mobile/certificate/CertificateUtils.kt | 2 +-
.../horizontal/tella/mobile/util/Extensions.kt | 11 ++++++++++-
.../fragment/peertopeer/PeerToPeerViewModel.kt | 2 +-
.../RecipientVerificationFragment.kt | 4 ++--
.../SenderManualConnectionFragment.kt | 18 ++++++++----------
.../senderflow/SenderVerificationFragment.kt | 3 ++-
.../layout/connect_manually_verification.xml | 1 +
.../res/layout/sender_manual_connection.xml | 4 ++--
8 files changed, 27 insertions(+), 18 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
index 53cb67a5e..1f12b1179 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
@@ -43,7 +43,7 @@ object CertificateUtils {
fun getPublicKeyHash(certificate: X509Certificate): String {
val digest = java.security.MessageDigest.getInstance("SHA-256")
val hash = digest.digest(certificate.publicKey.encoded)
- return hash.joinToString("") { "%02x".format(it) }
+ return hash.joinToString("") { "%04x".format(it) }
}
fun createSSLContext(
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt
index 6dede8d76..514cdf6d9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt
@@ -135,6 +135,15 @@ fun Context.isScreenReaderOn(): Boolean {
}
fun NavController.navigateSafe(destinationId: Int, bundle: Bundle? = null) {
- navigate(destinationId, bundle,)
+ navigate(destinationId, bundle)
+}
+
+fun String.formatHash(): String {
+ return this
+ .take(64) // take only the first 64 characters
+ .chunked(4) // split into groups of 4
+ .chunked(4) // make 4 lines
+ .joinToString("\n") { it.joinToString(" ") }
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index d21b04f0a..124fd569f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -35,7 +35,7 @@ import javax.inject.Inject
class PeerToPeerViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val peerClient: TellaPeerToPeerClient,
- private val peerToPeerManager: PeerToPeerManager
+ peerToPeerManager: PeerToPeerManager
) : ViewModel() {
var hasNavigatedToSuccessFragment = false
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index abe893111..94efa2a15 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -9,6 +9,7 @@ import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
+import org.horizontal.tella.mobile.util.formatHash
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
import javax.inject.Inject
@@ -42,7 +43,7 @@ class RecipientVerificationFragment :
private fun initView() {
lifecycleScope.launchWhenStarted {
viewModel.sessionInfo.collect { session ->
- binding.hashContentTextView.text = session?.hash
+ binding.hashContentTextView.text = session?.hash?.formatHash()
}
}
}
@@ -52,7 +53,6 @@ class RecipientVerificationFragment :
binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
bundle.putBoolean("isSender", false)
navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
-
}
binding.toolbar.backClickListener = {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index fe7c609c3..e16e51cce 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -24,10 +24,10 @@ class SenderManualConnectionFragment :
}
private fun initView() {
- binding.connectCode.onChange {
+ binding.ipAddress.onChange {
updateNextButtonState()
}
- binding.port.onChange {
+ binding.pin.onChange {
updateNextButtonState()
}
@@ -54,9 +54,8 @@ class SenderManualConnectionFragment :
}
private fun isInputValid(): Boolean {
- return binding.connectCode.text?.isNotBlank() == true &&
- binding.pin.text?.isNotBlank() == true &&
- binding.port.text?.isNotBlank() == true
+ return binding.ipAddress.text?.isNotBlank() == true &&
+ binding.pin.text?.isNotBlank() == true
}
private fun updateNextButtonState() {
@@ -71,10 +70,9 @@ class SenderManualConnectionFragment :
binding.toolbar.backClickListener = { nav().popBackStack() }
binding.backBtn.setOnClickListener { nav().popBackStack() }
binding.nextBtn.setOnClickListener {
- val ip = binding.connectCode.text.toString()
- val port = binding.port.text.toString()
+ val ip = binding.ipAddress.text.toString()
val pin = binding.pin.text.toString()
-
+ val port = binding.port.text.toString()
viewModel.setPeerSessionInfo(
PeerConnectionInfo(
ip = ip,
@@ -84,7 +82,7 @@ class SenderManualConnectionFragment :
) // Store values
viewModel.handleCertificate(
- ip = binding.connectCode.text.toString(),
+ ip = binding.ipAddress.text.toString(),
port = binding.port.text.toString(),
pin = binding.pin.text.toString()
)
@@ -96,7 +94,7 @@ class SenderManualConnectionFragment :
bundle.putString("payload", hash)
viewModel.setPeerSessionInfo(
PeerConnectionInfo(
- ip = binding.connectCode.text.toString(),
+ ip = binding.ipAddress.text.toString(),
port = binding.port.text.toString(),
pin = binding.pin.text.toString().toInt(),
hash = hash
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 611d870d6..caef5a10b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -7,6 +7,7 @@ import androidx.lifecycle.lifecycleScope
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
+import org.horizontal.tella.mobile.util.formatHash
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
@@ -40,7 +41,7 @@ class SenderVerificationFragment :
if (session != null) {
peerConnectionInfo = session
}
- binding.hashContentTextView.text = session?.hash
+ binding.hashContentTextView.text = session?.hash?.formatHash()
}
}
diff --git a/mobile/src/main/res/layout/connect_manually_verification.xml b/mobile/src/main/res/layout/connect_manually_verification.xml
index 67e6c4ffb..53d5235ed 100644
--- a/mobile/src/main/res/layout/connect_manually_verification.xml
+++ b/mobile/src/main/res/layout/connect_manually_verification.xml
@@ -63,6 +63,7 @@
Date: Tue, 24 Jun 2025 11:47:51 +0100
Subject: [PATCH 033/153] wip reject flow and refactor code
---
.../tella/mobile/util/NavigationManager.kt | 16 +++---
.../mobile/views/fragment/peertopeer/Event.kt | 20 +++++++
.../peertopeer/PeerToPeerViewModel.kt | 1 +
.../fragment/peertopeer/SenderViewModel.kt | 22 ++++----
.../peertopeer/WaitingFragmentSender.kt | 40 ++++++++++++++
...Fragment.kt => WaitingReceiverFragment.kt} | 52 +++++++++----------
.../receipentflow/QRCodeFragment.kt | 8 +--
.../receipentflow/RecipientSuccessFragment.kt | 2 +-
.../RecipientVerificationFragment.kt | 8 +--
.../receipentflow/ShowDeviceInfoFragment.kt | 4 +-
.../senderflow/PrepareUploadFragment.kt | 14 ++---
.../senderflow/SenderVerificationFragment.kt | 4 +-
.../res/navigation/peer_to_peer_graph.xml | 26 ++++++----
mobile/src/main/res/values/strings.xml | 3 ++
14 files changed, 143 insertions(+), 77 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/Event.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragmentSender.kt
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/{WaitingFragment.kt => WaitingReceiverFragment.kt} (53%)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index dbd59de0c..bbc243016 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -201,24 +201,24 @@ class NavigationManager(
navigateToWithBundle(R.id.action_deviceInfoScreen_to_recipientVerificationScreen)
}
- fun navigateFromQrCodeScreenToWaitingFragment() {
- navigateToWithBundle(R.id.action_qrCodeScreen_to_waitingFragment)
+ fun navigateFromQrCodeScreenToWaitingReceiverFragment() {
+ navigateToWithBundle(R.id.action_qrCodeScreen_to_waitingReceiverFragment)
}
- fun navigateFromPrepareUploadFragmentToWaitingFragment() {
- navigateToWithBundle(R.id.action_prepareUploadFragment_to_waitingFragment)
+ fun navigateFromPrepareUploadFragmentToWaitingSenderFragment() {
+ navigateToWithBundle(R.id.action_prepareUploadFragment_to_waitingSenderFragment)
}
fun navigateConnectManuallyVerificationFragmentToprepareUploadFragment(){
navigateToWithBundle(R.id.action_connectManuallyVerificationFragment_to_prepareUploadFragment)
}
- fun navigateFromRecipientVerificationScreenToWaitingFragment(){
- navigateToWithBundle(R.id.action_recipientVerificationScreen_to_waitingFragment)
+ fun navigateFromRecipientVerificationScreenToWaitingReceiverFragment(){
+ navigateToWithBundle(R.id.action_recipientVerificationScreen_to_waitingReceiverFragment)
}
- fun navigateFromWaitingFragmentToRecipientSuccessFragment(){
- navigateToWithBundle(R.id.action_waitingFragment_to_recipientSuccessFragment)
+ fun navigateFromWaitingReceiverFragmentToRecipientSuccessFragment(){
+ navigateToWithBundle(R.id.action_waitingReceiverFragment_to_recipientSuccessFragment)
}
fun navigateBackToStartNearBySharingFragmentAndClearBackStack() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/Event.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/Event.kt
new file mode 100644
index 000000000..17f216dde
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/Event.kt
@@ -0,0 +1,20 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+/**
+ * Created by wafa on 23/6/2025.
+ */
+class Event(private val content: T) {
+ private var hasBeenHandled = false
+
+ /** Returns the content if not handled, else null */
+ fun getContentIfNotHandled(): T? {
+ return if (hasBeenHandled) null
+ else {
+ hasBeenHandled = true
+ content
+ }
+ }
+
+ /** Always returns the content, even if already handled */
+ fun peekContent(): T = content
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 124fd569f..a0fb47958 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -223,6 +223,7 @@ class PeerToPeerViewModel @Inject constructor(
fun clearPrepareRequest() {
_incomingPrepareRequest.value = null
hasNavigatedToSuccessFragment = false
+
}
fun setPeerSessionInfo(info: PeerConnectionInfo) {
_sessionInfo.value = info
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index d370f1404..ba7445f7b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -1,25 +1,23 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer
-import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.hzontal.tella_vault.VaultFile
import dagger.hilt.android.lifecycle.HiltViewModel
-import dagger.hilt.android.qualifiers.ApplicationContext
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import org.apache.commons.httpclient.HttpException
+import kotlinx.coroutines.withContext
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.util.fromJsonToObjectList
import timber.log.Timber
-import java.io.File
import javax.inject.Inject
@@ -29,8 +27,9 @@ class SenderViewModel @Inject constructor(
) : ViewModel() {
private val _prepareResults = MutableLiveData()
val prepareResults: LiveData = _prepareResults
- private val _prepareRejected = MutableLiveData()
- val prepareRejected: LiveData = _prepareRejected
+ private val _prepareRejected = MutableLiveData>()
+ val prepareRejected: LiveData> = _prepareRejected
+
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
@@ -85,12 +84,15 @@ class SenderViewModel @Inject constructor(
Timber.d("Success: transmissionId = $transmissionId")
_prepareResults.postValue(PeerPrepareUploadResponse(transmissionId))
}.onFailure { error ->
- // if (error.message?.contains("403") == true) {
- _prepareRejected.postValue(true)
-
- }
+ // if (error.message?.contains("403") == true) {
+ withContext(Dispatchers.Main) {
+ _prepareRejected.value = Event(true)
+ }
}
}
+ }
+
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragmentSender.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragmentSender.kt
new file mode 100644
index 000000000..bc5f2fa73
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragmentSender.kt
@@ -0,0 +1,40 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.os.bundleOf
+import androidx.fragment.app.activityViewModels
+import androidx.navigation.fragment.findNavController
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.bus.SingleLiveEvent
+import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.hzontal.shared_ui.utils.DialogUtils
+
+/**
+ * Created by wafa on 3/6/2025.
+ */
+class WaitingSenderFragment :
+ BaseBindingFragment(FragmentWaitingBinding::inflate) {
+ private val viewModelSender: SenderViewModel by activityViewModels()
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ binding.toolbar.setStartTextTitle(getString(R.string.send_files))
+ binding.waitingText.text = getString(R.string.waiting_for_the_recipient_to_accept_files)
+
+ binding.toolbar.backClickListener = {
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
+
+ viewModelSender.prepareRejected.observe(viewLifecycleOwner) { event ->
+ event.getContentIfNotHandled()?.let { wasRejected ->
+ if (wasRejected) {
+ findNavController().previousBackStackEntry
+ ?.savedStateHandle
+ ?.set("transferRejected", true)
+ findNavController().popBackStack()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
similarity index 53%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
index cffd1010a..3db4cc313 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
@@ -2,7 +2,6 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import android.os.Bundle
import android.view.View
-import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
@@ -13,25 +12,30 @@ import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
*/
-class WaitingFragment :
+
+class WaitingReceiverFragment :
BaseBindingFragment(FragmentWaitingBinding::inflate) {
+
private val viewModel: PeerToPeerViewModel by activityViewModels()
- private val viewModelSender: SenderViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- val isSender = arguments?.getBoolean("isSender") ?: false
+ setupToolbar()
+ observeIncomingPrepareRequest()
+ observeSenderRejection()
+ }
- binding.toolbar.backClickListener = {
- navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
- }
- if (!isSender) {
- binding.toolbar.setStartTextTitle(getString(R.string.receive_files))
- binding.waitingText.text = getString(R.string.waiting_for_the_sender_to_share_files)
- } else {
- binding.toolbar.setStartTextTitle(getString(R.string.send_files))
- binding.waitingText.text = getString(R.string.waiting_for_the_recipient_to_accept_files)
+ private fun setupToolbar() {
+ binding.toolbar.apply {
+ setStartTextTitle(getString(R.string.receive_files))
+ backClickListener = {
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
}
+ binding.waitingText.text = getString(R.string.waiting_for_the_sender_to_share_files)
+ }
+
+ private fun observeIncomingPrepareRequest() {
viewModel.incomingPrepareRequest.observe(viewLifecycleOwner) { request ->
if (request != null && !viewModel.hasNavigatedToSuccessFragment) {
viewModel.hasNavigatedToSuccessFragment = true
@@ -39,33 +43,27 @@ class WaitingFragment :
val fileCount = request.files.size
bundle.putInt("fileCount", fileCount)
bundle.putString("sessionId", request.sessionId)
- navManager().navigateFromWaitingFragmentToRecipientSuccessFragment()
- }
- }
- viewModelSender.prepareRejected.observe(viewLifecycleOwner) { wasRejected ->
- if (wasRejected) {
- findNavController().previousBackStackEntry
- ?.savedStateHandle
- ?.set("prepare_upload_result", true)
-
- findNavController().popBackStack()
+ navManager().navigateFromWaitingReceiverFragmentToRecipientSuccessFragment()
}
}
+ }
+ private fun observeSenderRejection() {
val navBackStackEntry = findNavController().currentBackStackEntry
- navBackStackEntry?.savedStateHandle?.getLiveData("prepare_upload")
+ navBackStackEntry?.savedStateHandle
+ ?.getLiveData("receiverDeclined")
?.observe(viewLifecycleOwner) { wasRejected ->
if (wasRejected) {
DialogUtils.showBottomMessage(
- baseActivity, "Sender's files rejected.",
- true
+ baseActivity,
+ getString(R.string.sender_files_rejected),
+ isError = true
)
}
}
}
-
override fun onStop() {
super.onStop()
viewModel.clearPrepareRequest()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 41fa4c4fc..1d767fb51 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -47,8 +47,8 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
// Navigate to the next screen
- bundle.putBoolean("isSender", false)
- navManager().navigateFromQrCodeScreenToWaitingFragment()
+ // bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
// reset the LiveData state if we want to consume event once
viewModel.resetRegistrationState()
} else {
@@ -116,8 +116,8 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
private fun initObservers() {
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- bundle.putBoolean("isSender", false)
- navManager().navigateFromQrCodeScreenToWaitingFragment()
+ // bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
} else {
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 21dcc8418..5fb8abca2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -51,7 +51,7 @@ class RecipientSuccessFragment : BaseBindingFragment
if (success) {
// Navigate to the next screen
- bundle.putBoolean("isSender", false)
- navManager().navigateFromQrCodeScreenToWaitingFragment()
+ // bundle.putBoolean("isSender", false)
+ navManager().navigateFromWaitingReceiverFragmentToRecipientSuccessFragment()
// reset the LiveData state if we want to consume event once
viewModel.resetRegistrationState()
} else {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index ecde5ea79..422700a3d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -97,11 +97,11 @@ class PrepareUploadFragment :
}
val navBackStackEntry = findNavController().currentBackStackEntry
navBackStackEntry?.savedStateHandle
- ?.getLiveData("prepare_upload_result")
+ ?.getLiveData("transferRejected")
?.observe(viewLifecycleOwner) { wasRejected ->
if (wasRejected) {
DialogUtils.showBottomMessage(
- baseActivity, "Recipient rejected the files.",
+ baseActivity, getString(R.string.recipient_rejected_the_files),
true
)
}
@@ -111,7 +111,7 @@ class PrepareUploadFragment :
val id = response.transmissionId
DialogUtils.showBottomMessage(
baseActivity,
- "The receiver accepted the files transfer ",
+ getString(R.string.the_receiver_accepted_the_files_transfer),
false,
3000
)
@@ -139,12 +139,8 @@ class PrepareUploadFragment :
private fun checkIsNewDraftEntry() {
if (isNewDraft) {
- // binding.deleteBtn.invisible()
- // binding.sendLaterBtn.show()
binding.sendReportBtn.text = getString(R.string.collect_end_action_submit)
} else {
- // binding.deleteBtn.show()
- // binding.sendLaterBtn.invisible()
binding.sendReportBtn.text = getString(R.string.Send_Action_Label)
}
}
@@ -304,8 +300,8 @@ class PrepareUploadFragment :
if (selectedFiles.isNotEmpty()) {
viewModel.prepareUploadsFromVaultFiles(selectedFiles)
// navigate to waiting view
- bundle.putBoolean("isSender", true)
- navManager().navigateFromPrepareUploadFragmentToWaitingFragment()
+ //bundle.putBoolean("isSender", true)
+ navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
} else {
showToast("No file selected")
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index caef5a10b..caa9cf423 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -64,8 +64,8 @@ class SenderVerificationFragment :
viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
// Navigate to the next screen
- bundle.putBoolean("isSender", false)
- navManager().navigateFromQrCodeScreenToWaitingFragment()
+ // bundle.putBoolean("isSender", false)
+ navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
// reset the LiveData state if we want to consume event once
viewModel.resetRegistrationState()
} else {
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 1442900e1..effc7eff2 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -63,8 +63,8 @@
android:id="@+id/action_qrCodeScreen_to_deviceInfoScreen"
app:destination="@id/deviceInfoScreen" />
+ android:id="@+id/action_qrCodeScreen_to_waitingReceiverFragment"
+ app:destination="@id/waitingReceiverFragment" />
+ android:id="@+id/action_recipientVerificationScreen_to_waitingReceiverFragment"
+ app:destination="@id/waitingReceiverFragment" />
+ android:id="@+id/action_prepareUploadFragment_to_waitingSenderFragment"
+ app:destination="@id/waitingSenderFragment" />
+ android:label="WaitingReceiverFragment" >
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index 9bfebd469..e63f72737 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1048,4 +1048,7 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Exit nearby sharing?
Your progress will be lost.
IP address
+ Sender\'s files rejected.
+ "The receiver accepted the files transfer "
+ Recipient rejected the files.
From 1302359389da5235e50c434394d0324411b988ad Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 24 Jun 2025 12:29:06 +0100
Subject: [PATCH 034/153] change naming
---
.../views/fragment/peertopeer/WaitingReceiverFragment.kt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
index 3db4cc313..67f98f5d2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
@@ -21,7 +21,7 @@ class WaitingReceiverFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupToolbar()
observeIncomingPrepareRequest()
- observeSenderRejection()
+ observeReceiverRejection()
}
private fun setupToolbar() {
@@ -49,7 +49,7 @@ class WaitingReceiverFragment :
}
}
- private fun observeSenderRejection() {
+ private fun observeReceiverRejection() {
val navBackStackEntry = findNavController().currentBackStackEntry
navBackStackEntry?.savedStateHandle
?.getLiveData("receiverDeclined")
From a34f59b49d143ecebc5111279def2e425b51f313 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 24 Jun 2025 17:00:58 +0100
Subject: [PATCH 035/153] WIP manual register flow
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 34 +++++++++++--------
.../domain/peertopeer/IncomingRegistration.kt | 6 ++++
.../fragment/peertopeer/PeerEventManager.kt | 21 ++++++++++--
.../peertopeer/PeerToPeerViewModel.kt | 17 ++++++++++
.../RecipientVerificationFragment.kt | 29 ++++++++++++++--
.../senderflow/SenderVerificationFragment.kt | 16 ++++-----
6 files changed, 93 insertions(+), 30 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/IncomingRegistration.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index d92cbea5b..f37804b4f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -22,6 +22,7 @@ import io.ktor.server.routing.routing
import kotlinx.coroutines.launch
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.suspendCancellableCoroutine
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
@@ -34,6 +35,7 @@ import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.util.UUID
+import kotlin.coroutines.Continuation
const val port = 53317
@@ -51,6 +53,9 @@ class TellaPeerToPeerServer(
override val certificatePem: String
get() = CertificateUtils.certificateToPem(certificate)
+ private val pendingRegistrations = mutableMapOf>()
+
+
override fun start() {
val keyStore = KeyStore.getInstance("PKCS12").apply {
load(null, null)
@@ -96,27 +101,25 @@ class TellaPeerToPeerServer(
val request = try {
call.receive()
} catch (e: Exception) {
- call.respondText(
- """{"error": "Invalid request body"}""",
- ContentType.Application.Json,
- HttpStatusCode.BadRequest
- )
+ call.respond(HttpStatusCode.BadRequest, "Invalid request body")
return@post
}
- val sessionId = UUID.randomUUID().toString()
+ val registrationId = UUID.randomUUID().toString()
- // Emit registration success event asynchronously
+ val accepted = PeerEventManager.emitIncomingRegistrationRequest(registrationId, request)
+
+ if (!accepted) {
+ call.respond(HttpStatusCode.Forbidden, "Receiver rejected the registration")
+ return@post
+ }
+
+ val sessionId = registrationId // or generate a separate one
launch {
PeerEventManager.emitRegistrationSuccess()
}
- call.respondText(
- Gson().toJson(PeerResponse(sessionId)),
- ContentType.Application.Json,
- HttpStatusCode.OK
- )
-
+ call.respond(HttpStatusCode.OK, PeerResponse(sessionId))
}
post("/api/v1/prepare-upload") {
val request = try {
@@ -135,7 +138,10 @@ class TellaPeerToPeerServer(
if (accepted) {
val transmissionId = UUID.randomUUID().toString()
- call.respond(HttpStatusCode.OK, PeerPrepareUploadResponse(transmissionId))
+ call.respond(
+ HttpStatusCode.OK,
+ PeerPrepareUploadResponse(transmissionId)
+ )
} else {
call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/IncomingRegistration.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/IncomingRegistration.kt
new file mode 100644
index 000000000..bc983a3f3
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/IncomingRegistration.kt
@@ -0,0 +1,6 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+data class IncomingRegistration(
+ val registrationId: String,
+ val payload: PeerRegisterPayload
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
index 8185f82a8..26c2e1c9a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
@@ -1,12 +1,10 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer
-import io.ktor.http.HttpStatusCode
-import io.ktor.server.application.ApplicationCall
-import io.ktor.server.response.respond
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
+import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
/**
* Created by wafa on 3/6/2025.
@@ -15,6 +13,12 @@ object PeerEventManager {
// MutableSharedFlow to emit registration events, replay 1 to send last event to new collectors
val registrationEvents = MutableSharedFlow(replay = 1)
+ private val _registrationRequests = MutableSharedFlow>(replay = 1)
+ val registrationRequests = _registrationRequests.asSharedFlow()
+
+ private val registrationDecisionMap = mutableMapOf>()
+
+
// Call this when registration succeeds
suspend fun emitRegistrationSuccess() {
@@ -39,4 +43,15 @@ object PeerEventManager {
fun resolveUserDecision(sessionId: String, accepted: Boolean) {
decisionMap.remove(sessionId)?.complete(accepted)
}
+
+ suspend fun emitIncomingRegistrationRequest(registrationId: String, payload: PeerRegisterPayload): Boolean {
+ val deferred = CompletableDeferred()
+ registrationDecisionMap[registrationId] = deferred
+ _registrationRequests.emit(registrationId to payload)
+ return deferred.await()
+ }
+
+ fun confirmRegistration(registrationId: String, accepted: Boolean) {
+ registrationDecisionMap.remove(registrationId)?.complete(accepted)
+ }
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index a0fb47958..11d0f1249 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -24,6 +24,7 @@ import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
import org.horizontal.tella.mobile.views.fragment.peertopeer.data.NetworkInfo
import timber.log.Timber
@@ -55,6 +56,8 @@ class PeerToPeerViewModel @Inject constructor(
val registrationServerSuccess: LiveData = _registrationServerSuccess
private val _incomingPrepareRequest = MutableLiveData()
val incomingPrepareRequest: MutableLiveData = _incomingPrepareRequest
+ private val _incomingRequest = MutableStateFlow(null)
+ val incomingRequest: StateFlow = _incomingRequest
init {
viewModelScope.launch {
@@ -68,6 +71,12 @@ class PeerToPeerViewModel @Inject constructor(
_registrationServerSuccess.postValue(success)
}
}
+
+ viewModelScope.launch {
+ PeerEventManager.registrationRequests.collect { (registrationId, payload) ->
+ _incomingRequest.value = IncomingRegistration(registrationId, payload)
+ }
+ }
}
fun resetRegistrationState() {
@@ -220,6 +229,14 @@ class PeerToPeerViewModel @Inject constructor(
}
}
+ fun onUserConfirmedRegistration(registrationId: String) {
+ PeerEventManager.confirmRegistration(registrationId, accepted = true)
+ }
+
+ fun onUserRejectedRegistration(registrationId: String) {
+ PeerEventManager.confirmRegistration(registrationId, accepted = false)
+ }
+
fun clearPrepareRequest() {
_incomingPrepareRequest.value = null
hasNavigatedToSuccessFragment = false
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index c698a5dea..1901eb5ee 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -3,8 +3,11 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.google.gson.Gson
+import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
@@ -29,12 +32,32 @@ class RecipientVerificationFragment :
}
initListeners()
initView()
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ viewModel.incomingRequest.collect { request ->
+ if (request != null) {
+ binding.confirmAndConnectBtn.isEnabled = true
+ binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
+
+ // Set the click listener when the request is available
+ binding.confirmAndConnectBtn.setOnClickListener {
+ viewModel.onUserConfirmedRegistration(request.registrationId)
+ }
+ } else {
+ binding.confirmAndConnectBtn.isEnabled = false
+ binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange16_btn)
+ binding.confirmAndConnectBtn.setOnClickListener(null) // Optional: clear listener
+ }
+ }
+ }
+ }
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
binding.confirmAndConnectBtn.setOnClickListener {
- // bundle.putBoolean("isSender", false)
- navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
+
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index caa9cf423..f80d6a199 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -3,7 +3,10 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
@@ -61,16 +64,9 @@ class SenderVerificationFragment :
private fun initObservers() {
- viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
- if (success) {
- // Navigate to the next screen
- // bundle.putBoolean("isSender", false)
- navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
- // reset the LiveData state if we want to consume event once
- viewModel.resetRegistrationState()
- } else {
- }
- }
+
+
+
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
navManager().navigateConnectManuallyVerificationFragmentToprepareUploadFragment()
From a430931e9e820ed31a40ebfbc6915072b47bf0b4 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Thu, 26 Jun 2025 16:29:40 +0100
Subject: [PATCH 036/153] Revert "change the connectCode to ipAdress"
This reverts commit d311889ecbcd20913709d15e7fa7511f9afb234f.
---
.../tella/mobile/domain/peertopeer/PeerConnectionPayload.kt | 4 ++--
.../views/fragment/peertopeer/receipentflow/QRCodeFragment.kt | 2 +-
.../peertopeer/receipentflow/ShowDeviceInfoFragment.kt | 4 ++--
.../fragment/peertopeer/senderflow/ScanQrCodeFragment.kt | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
index 81bb98411..7a28595c5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
@@ -3,8 +3,8 @@ package org.horizontal.tella.mobile.domain.peertopeer
import com.google.gson.annotations.SerializedName
data class PeerConnectionPayload(
- @SerializedName("ip_address")
- val ipAdress: String,
+ @SerializedName("connect_code")
+ val connectCode: String,
@SerializedName("port")
val port: Int,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 1d767fb51..b1082a021 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -69,7 +69,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val port = port
payload = PeerConnectionPayload(
- ipAdress = ip,
+ connectCode = ip,
port = port,
certificateHash = certHash,
pin = pin
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 88afc2975..60937962a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -30,7 +30,7 @@ class ShowDeviceInfoFragment :
}
private fun initView() {
- binding.connectCode.setRightText(payload?.ipAdress)
+ binding.connectCode.setRightText(payload?.connectCode)
binding.pin.setRightText(payload?.pin)
binding.port.setRightText(payload?.port.toString())
}
@@ -45,7 +45,7 @@ class ShowDeviceInfoFragment :
viewModel.clientHash.collect { hash ->
viewModel.setPeerSessionInfo(
PeerConnectionInfo(
- ip = payload?.ipAdress.toString(),
+ ip = payload?.connectCode.toString(),
port = payload?.port.toString(),
pin = payload?.pin?.toInt()!!,
hash = hash
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 8e06174a1..99e265911 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -61,7 +61,7 @@ class ScanQrCodeFragment :
val payload = Gson().fromJson(qrContent, PeerConnectionPayload::class.java)
viewModel.startRegistration(
- ip = payload.ipAdress,
+ ip = payload.connectCode,
port = payload.port.toString(),
hash = payload.certificateHash,
pin = payload.pin
From f717ab3611394f996bf1ee47ebb5972e0819e69d Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Thu, 26 Jun 2025 20:28:36 +0100
Subject: [PATCH 037/153] Finish connect flow
---
mobile/src/main/AndroidManifest.xml | 1 +
.../data/peertopeer/TellaPeerToPeerClient.kt | 4 ++--
.../data/peertopeer/TellaPeerToPeerServer.kt | 10 ++--------
.../{ => remote}/PrepareUploadRequest.kt | 3 ++-
.../{data => domain}/peertopeer/FileItem.kt | 2 +-
.../fragment/peertopeer/PeerEventManager.kt | 2 +-
.../peertopeer/PeerToPeerViewModel.kt | 9 ++++++---
.../receipentflow/QRCodeFragment.kt | 9 +++------
.../RecipientVerificationFragment.kt | 20 +++++++++----------
9 files changed, 28 insertions(+), 32 deletions(-)
rename mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/{ => remote}/PrepareUploadRequest.kt (66%)
rename mobile/src/main/java/org/horizontal/tella/mobile/{data => domain}/peertopeer/FileItem.kt (78%)
diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml
index 37ad47641..bdc0b94e2 100644
--- a/mobile/src/main/AndroidManifest.xml
+++ b/mobile/src/main/AndroidManifest.xml
@@ -34,6 +34,7 @@
+
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index d0682d980..2eacbadc8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -11,9 +11,10 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
+import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.json.JSONObject
-import java.io.File
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
@@ -74,7 +75,6 @@ class TellaPeerToPeerClient {
val jsonPayload = Json.encodeToString(payload)
val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
- Log.d("PeerClient", "Request payload: $requestBody")
val client = getClientWithFingerprintValidation(expectedFingerprint)
val request = Request.Builder()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index f37804b4f..c66cd3f48 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -1,8 +1,6 @@
package org.horizontal.tella.mobile.data.peertopeer
import android.util.Log
-import com.google.gson.Gson
-import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.call
@@ -19,12 +17,12 @@ import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
-import kotlinx.coroutines.launch
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
@@ -35,7 +33,6 @@ import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.util.UUID
-import kotlin.coroutines.Continuation
const val port = 53317
@@ -53,9 +50,6 @@ class TellaPeerToPeerServer(
override val certificatePem: String
get() = CertificateUtils.certificateToPem(certificate)
- private val pendingRegistrations = mutableMapOf>()
-
-
override fun start() {
val keyStore = KeyStore.getInstance("PKCS12").apply {
load(null, null)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
similarity index 66%
rename from mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
index 2653e826a..803f30c08 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PrepareUploadRequest.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
@@ -1,7 +1,8 @@
-package org.horizontal.tella.mobile.data.peertopeer
+package org.horizontal.tella.mobile.data.peertopeer.remote
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
+import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
@Serializable
data class PrepareUploadRequest(
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/FileItem.kt
similarity index 78%
rename from mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/FileItem.kt
index 8c4071fac..f089be108 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/FileItem.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/FileItem.kt
@@ -1,4 +1,4 @@
-package org.horizontal.tella.mobile.data.peertopeer
+package org.horizontal.tella.mobile.domain.peertopeer
import kotlinx.serialization.Serializable
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
index 26c2e1c9a..5b4da64b0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
@@ -3,7 +3,7 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
-import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
/**
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 11d0f1249..e939abaf0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
-import org.horizontal.tella.mobile.data.peertopeer.PrepareUploadRequest
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
@@ -230,10 +230,13 @@ class PeerToPeerViewModel @Inject constructor(
}
fun onUserConfirmedRegistration(registrationId: String) {
- PeerEventManager.confirmRegistration(registrationId, accepted = true)
+ viewModelScope.launch {
+ PeerEventManager.confirmRegistration(registrationId, true)
+ _registrationSuccess.postValue(true)
+ }
}
-
fun onUserRejectedRegistration(registrationId: String) {
+ //TODO when the user reject i THINK the client should go back to the
PeerEventManager.confirmRegistration(registrationId, accepted = false)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index b1082a021..4a643d659 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -17,7 +17,6 @@ import org.horizontal.tella.mobile.data.peertopeer.port
import org.horizontal.tella.mobile.databinding.FragmentQrCodeBinding
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
-import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
import javax.inject.Inject
@@ -26,9 +25,9 @@ import javax.inject.Inject
class QRCodeFragment : BaseBindingFragment(FragmentQrCodeBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
- private var server: TellaServer? = null
private var payload: PeerConnectionPayload? = null
private lateinit var qrPayload: String
+
@Inject
lateinit var peerServerStarterManager: PeerServerStarterManager
@@ -47,7 +46,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
// Navigate to the next screen
- // bundle.putBoolean("isSender", false)
+ // bundle.putBoolean("isSender", false)
navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
// reset the LiveData state if we want to consume event once
viewModel.resetRegistrationState()
@@ -63,7 +62,6 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
peerServerStarterManager.startServer(ip, keyPair, certificate, config)
-
val certHash = CertificateUtils.getPublicKeyHash(certificate)
val pin = (100000..999999).random().toString()
val port = port
@@ -79,7 +77,6 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
generateQrCode(qrPayload)
}
-
private fun generateQrCode(content: String) {
try {
val barcodeEncoder = BarcodeEncoder()
@@ -116,7 +113,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
private fun initObservers() {
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- // bundle.putBoolean("isSender", false)
+ bundle.putBoolean("isSender", false)
navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
} else {
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 1901eb5ee..c2210ab67 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -44,6 +44,12 @@ class RecipientVerificationFragment :
binding.confirmAndConnectBtn.setOnClickListener {
viewModel.onUserConfirmedRegistration(request.registrationId)
}
+
+ binding.discardBtn.setOnClickListener {
+ peerServerStarterManager.stopServer()
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ viewModel.onUserRejectedRegistration(request.registrationId)
+ }
} else {
binding.confirmAndConnectBtn.isEnabled = false
binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange16_btn)
@@ -54,11 +60,8 @@ class RecipientVerificationFragment :
}
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- bundle.putBoolean("isSender", false)
- navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
- binding.confirmAndConnectBtn.setOnClickListener {
-
- }
+ bundle.putBoolean("isSender", false)
+ navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
}
}
}
@@ -72,11 +75,6 @@ class RecipientVerificationFragment :
}
private fun initListeners() {
- binding.confirmAndConnectBtn.setOnClickListener {
- binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
- // bundle.putBoolean("isSender", false)
- navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
- }
binding.toolbar.backClickListener = {
peerServerStarterManager.stopServer()
@@ -87,6 +85,8 @@ class RecipientVerificationFragment :
peerServerStarterManager.stopServer()
navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
+
+ binding.confirmAndConnectBtn.setOnClickListener(null)
}
}
\ No newline at end of file
From 2b180cb93f0f8c9bfac61c62d591b6c463dbb7f6 Mon Sep 17 00:00:00 2001
From: wafa
Date: Fri, 27 Jun 2025 11:02:44 +0100
Subject: [PATCH 038/153] finish reject flow
---
.../{WaitingFragmentSender.kt => WaitingSenderFragment.kt} | 7 +++----
.../receipentflow/RecipientVerificationFragment.kt | 5 ++++-
.../peertopeer/senderflow/PrepareUploadFragment.kt | 5 +++--
3 files changed, 10 insertions(+), 7 deletions(-)
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/{WaitingFragmentSender.kt => WaitingSenderFragment.kt} (87%)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragmentSender.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingSenderFragment.kt
similarity index 87%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragmentSender.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingSenderFragment.kt
index bc5f2fa73..5a3bc4340 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingFragmentSender.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingSenderFragment.kt
@@ -2,14 +2,12 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer
import android.os.Bundle
import android.view.View
-import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
+import com.hzontal.tella_vault.VaultFile
import org.horizontal.tella.mobile.R
-import org.horizontal.tella.mobile.bus.SingleLiveEvent
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
@@ -21,7 +19,8 @@ class WaitingSenderFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.toolbar.setStartTextTitle(getString(R.string.send_files))
binding.waitingText.text = getString(R.string.waiting_for_the_recipient_to_accept_files)
-
+ val selectedFiles = arguments?.getSerializable("selectedFiles") as? List ?: emptyList()
+ viewModelSender.prepareUploadsFromVaultFiles(selectedFiles)
binding.toolbar.backClickListener = {
navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index c2210ab67..7781897fd 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -60,7 +60,10 @@ class RecipientVerificationFragment :
}
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- bundle.putBoolean("isSender", false)
+ bundle.putBoolean("isSender", false)
+ // navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
+ binding.confirmAndConnectBtn.setOnClickListener {
+ // bundle.putBoolean("isSender", false)
navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 422700a3d..476c26574 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -298,10 +298,11 @@ class PrepareUploadFragment :
if (isSubmitEnabled) {
val selectedFiles = filesRecyclerViewAdapter.getFiles()
if (selectedFiles.isNotEmpty()) {
- viewModel.prepareUploadsFromVaultFiles(selectedFiles)
+ bundle.putSerializable("selectedFiles", ArrayList(selectedFiles)) // assuming VaultFile is Serializable
+ navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
+ //viewModel.prepareUploadsFromVaultFiles(selectedFiles)
// navigate to waiting view
//bundle.putBoolean("isSender", true)
- navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
} else {
showToast("No file selected")
}
From 6b126e0c1d39b40cabdab9c73494fc4e39f63686 Mon Sep 17 00:00:00 2001
From: wafa
Date: Fri, 27 Jun 2025 11:09:45 +0100
Subject: [PATCH 039/153] fix merge conflicts
---
.../receipentflow/RecipientVerificationFragment.kt | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 7781897fd..acaa3bbe0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -61,10 +61,9 @@ class RecipientVerificationFragment :
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
bundle.putBoolean("isSender", false)
- // navManager().navigateFromRecipientVerificationScreenToWaitingFragment()
- binding.confirmAndConnectBtn.setOnClickListener {
- // bundle.putBoolean("isSender", false)
- navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
+ /// binding.confirmAndConnectBtn.setOnClickListener {
+ navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
+ // }
}
}
}
From c4d338cc9397a8086b86196556e9c4c8aba887e8 Mon Sep 17 00:00:00 2001
From: wafa
Date: Mon, 30 Jun 2025 12:18:11 +0100
Subject: [PATCH 040/153] delete old code
---
.../peertopeer/receipentflow/RecipientVerificationFragment.kt | 3 ---
1 file changed, 3 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index acaa3bbe0..67181b4be 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -60,10 +60,7 @@ class RecipientVerificationFragment :
}
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- bundle.putBoolean("isSender", false)
- /// binding.confirmAndConnectBtn.setOnClickListener {
navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
- // }
}
}
}
From a195b50842e7939621fc64c33232807efb449f53 Mon Sep 17 00:00:00 2001
From: wafa
Date: Mon, 30 Jun 2025 15:12:25 +0100
Subject: [PATCH 041/153] wip import files
---
.../peertopeer/activity/PeerToPeerActivity.kt | 58 +++++++++++++++++++
.../senderflow/PrepareUploadFragment.kt | 21 +------
2 files changed, 60 insertions(+), 19 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
index 83c42259f..69ea4fe4b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/activity/PeerToPeerActivity.kt
@@ -2,24 +2,82 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.activity
import android.content.Intent
import android.os.Bundle
+import androidx.activity.viewModels
+import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.google.gson.Gson
+import com.hzontal.tella_vault.VaultFile
+import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.ActivityPeerToPeerBinding
+import org.horizontal.tella.mobile.mvvm.media.MediaImportViewModel
+import org.horizontal.tella.mobile.util.C
import org.horizontal.tella.mobile.views.base_ui.BaseLockActivity
+import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.VAULT_FILE_KEY
+import timber.log.Timber
class PeerToPeerActivity : BaseLockActivity() {
private lateinit var binding: ActivityPeerToPeerBinding
+ private val mediaImportViewModel: MediaImportViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPeerToPeerBinding.inflate(layoutInflater)
setContentView(binding.getRoot())
+ initObservers()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
+ // Handle import results
+ if (requestCode == C.IMPORT_VIDEO || requestCode == C.IMPORT_IMAGE || requestCode == C.IMPORT_FILE) {
+ handleImportResult(requestCode, data)
+ return
+ }
+
// Delegate onActivityResult to child fragments
supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
it.onActivityResult(requestCode, resultCode, data)
}
+
+ }
+
+ private fun handleImportResult(requestCode: Int, data: Intent?) {
+ try {
+ if (data != null) {
+ val uri = data.data
+ if (uri != null) {
+ divviupUtils.runFileImportEvent()
+ when (requestCode) {
+ C.IMPORT_FILE -> mediaImportViewModel.importFile(uri)
+ }
+ }
+ }
+ } catch (e: NullPointerException) {
+ // Handle null pointer exception
+ showToast(R.string.gallery_toast_fail_importing_file)
+ FirebaseCrashlytics.getInstance().recordException(e)
+ Timber.e(e, "NullPointerException occurred: ${e.message}")
+ } catch (e: Exception) {
+ // Handle other exceptions
+ FirebaseCrashlytics.getInstance().recordException(e)
+ Timber.e(e, "NullPointerException occurred: ${e.message}")
+ }
+ }
+
+ private fun onMediaFileImported(vaultFile: VaultFile) {
+ val list: MutableList = ArrayList()
+ list.add(vaultFile.id)
+ onActivityResult(
+ C.MEDIA_FILE_ID, RESULT_OK, Intent().putExtra(VAULT_FILE_KEY, Gson().toJson(list))
+ )
+ }
+
+ private fun onImportError(throwable: Throwable?) {
+ Timber.d(throwable)
+ }
+
+ private fun initObservers() {
+ mediaImportViewModel.mediaFileLiveData.observe(this, ::onMediaFileImported)
+ mediaImportViewModel.importError.observe(this, ::onImportError)
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 476c26574..c0564ef3d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -256,16 +256,7 @@ class PrepareUploadFragment :
}
private fun putFiles(vaultFileList: List) {
- val filteredFiles = vaultFileList.filter { file ->
- isValidFile(file)
- }.also {
- if (it.size != vaultFileList.size) {
- showToast(getString(R.string.nextcloud_file_size_limit))
- }
- }
-
- // Insert the filtered files
- filteredFiles.forEach { file ->
+ vaultFileList.forEach { file ->
filesRecyclerViewAdapter.insertAttachment(file)
}
@@ -299,10 +290,8 @@ class PrepareUploadFragment :
val selectedFiles = filesRecyclerViewAdapter.getFiles()
if (selectedFiles.isNotEmpty()) {
bundle.putSerializable("selectedFiles", ArrayList(selectedFiles)) // assuming VaultFile is Serializable
- navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
- //viewModel.prepareUploadsFromVaultFiles(selectedFiles)
// navigate to waiting view
- //bundle.putBoolean("isSender", true)
+ navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
} else {
showToast("No file selected")
}
@@ -322,12 +311,6 @@ class PrepareUploadFragment :
)
}
- // Helper function to check if the file is valid (less than or equal to 20MB)
- private fun isValidFile(file: VaultFile): Boolean {
- val isFileSizeValid = file.size <= 20 * 1024 * 1024 // 20MB in bytes
- return isFileSizeValid
- }
-
override fun playMedia(mediaFile: VaultFile?) {
}
From 874597dabe7bbd655fa10e41e3e6c121279aa002 Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 1 Jul 2025 12:20:10 +0100
Subject: [PATCH 042/153] fix hash generation to match the ios
---
.../horizontal/tella/mobile/certificate/CertificateUtils.kt | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
index 1f12b1179..25431735a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateUtils.kt
@@ -40,10 +40,11 @@ object CertificateUtils {
fun decodeBase64(encodedString: String): ByteArray =
Base64.decode(encodedString, Base64.NO_WRAP)
+
fun getPublicKeyHash(certificate: X509Certificate): String {
val digest = java.security.MessageDigest.getInstance("SHA-256")
- val hash = digest.digest(certificate.publicKey.encoded)
- return hash.joinToString("") { "%04x".format(it) }
+ val hash = digest.digest(certificate.encoded)
+ return hash.joinToString("") { "%02x".format(it) } // <-- fix here
}
fun createSSLContext(
From 30862cb77d0c1084729167dd46e7263960538aa9 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 1 Jul 2025 14:08:16 +0100
Subject: [PATCH 043/153] Fix qr code flow
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 46 +++++++++++--------
.../data/peertopeer/TellaPeerToPeerServer.kt | 10 ++--
.../domain/peertopeer/PeerRegisterPayload.kt | 3 +-
.../tella/mobile/util/Extensions.kt | 3 --
.../peertopeer/PeerToPeerViewModel.kt | 14 +++++-
.../senderflow/ScanQrCodeFragment.kt | 3 +-
.../senderflow/SenderVerificationFragment.kt | 5 +-
7 files changed, 53 insertions(+), 31 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 2eacbadc8..236542047 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -62,7 +62,8 @@ class TellaPeerToPeerClient {
ip: String,
port: String,
expectedFingerprint: String,
- pin: String
+ pin: String,
+ autoUpload: Boolean
): Result = withContext(Dispatchers.IO) {
val url = "https://$ip:$port/api/v1/register"
Log.d("PeerClient", "Connecting to: $url")
@@ -70,7 +71,8 @@ class TellaPeerToPeerClient {
try {
val payload = PeerRegisterPayload(
pin = pin,
- nonce = UUID.randomUUID().toString()
+ nonce = UUID.randomUUID().toString(),
+ autoUpload
)
val jsonPayload = Json.encodeToString(payload)
@@ -162,8 +164,16 @@ class TellaPeerToPeerClient {
} else {
Log.e("PrepareUpload", "Server error ${response.code}: ${response.message}")
when (response.code) {
- 400 -> Log.e("PrepareUpload", "Bad Request – likely missing or invalid fields.")
- 403 -> Log.e("PrepareUpload", "Forbidden – the server is refusing the request.")
+ 400 -> Log.e(
+ "PrepareUpload",
+ "Bad Request – likely missing or invalid fields."
+ )
+
+ 403 -> Log.e(
+ "PrepareUpload",
+ "Forbidden – the server is refusing the request."
+ )
+
409 -> Log.e("PrepareUpload", "Conflict – maybe another active session.")
500 -> Log.e("PrepareUpload", "Internal Server Error – try again later.")
else -> Log.e("PrepareUpload", "Unhandled server error code.")
@@ -179,21 +189,21 @@ class TellaPeerToPeerClient {
}
- suspend fun fetchServerFingerprint(ip: String, port: Int): Result = withContext(Dispatchers.IO) {
- try {
- val socket = SSLSocketFactory.getDefault()
- .createSocket(ip, port) as SSLSocket
- socket.soTimeout = 5000
- socket.startHandshake()
-
- val cert = socket.session.peerCertificates[0] as X509Certificate
- val fingerprint = CertificateUtils.getPublicKeyHash(cert)
- Result.success(fingerprint)
- } catch (e: Exception) {
- Result.failure(e)
- }
- }
+ suspend fun fetchServerFingerprint(ip: String, port: Int): Result =
+ withContext(Dispatchers.IO) {
+ try {
+ val socket = SSLSocketFactory.getDefault()
+ .createSocket(ip, port) as SSLSocket
+ socket.soTimeout = 5000
+ socket.startHandshake()
+ val cert = socket.session.peerCertificates[0] as X509Certificate
+ val fingerprint = CertificateUtils.getPublicKeyHash(cert)
+ Result.success(fingerprint)
+ } catch (e: Exception) {
+ Result.failure(e)
+ }
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index c66cd3f48..c479a53b7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -101,20 +101,24 @@ class TellaPeerToPeerServer(
val registrationId = UUID.randomUUID().toString()
- val accepted = PeerEventManager.emitIncomingRegistrationRequest(registrationId, request)
+ val accepted = if (request.autoAccept) {
+ true // Automatically accept
+ } else {
+ PeerEventManager.emitIncomingRegistrationRequest(registrationId, request)
+ }
if (!accepted) {
call.respond(HttpStatusCode.Forbidden, "Receiver rejected the registration")
return@post
}
- val sessionId = registrationId // or generate a separate one
launch {
PeerEventManager.emitRegistrationSuccess()
}
- call.respond(HttpStatusCode.OK, PeerResponse(sessionId))
+ call.respond(HttpStatusCode.OK, PeerResponse(registrationId))
}
+
post("/api/v1/prepare-upload") {
val request = try {
call.receive()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
index d9c399056..fc5f65d2b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
@@ -6,5 +6,6 @@ import java.util.UUID
@Serializable
data class PeerRegisterPayload(
val pin: String,
- val nonce: String = UUID.randomUUID().toString()
+ val nonce: String = UUID.randomUUID().toString(),
+ val autoAccept: Boolean = false,
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt
index 514cdf6d9..3e4cb8ba6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/Extensions.kt
@@ -18,9 +18,6 @@ import androidx.navigation.NavController
import com.google.gson.Gson
import com.google.gson.JsonParseException
import com.google.gson.reflect.TypeToken
-/*import org. cleaninsights.sdk.Campaign
-import org.cleaninsights.sdk.CleanInsights
-import org.cleaninsights.sdk.CleanInsightsConfiguration*/
import timber.log.Timber
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index e939abaf0..56913d24a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -82,9 +82,11 @@ class PeerToPeerViewModel @Inject constructor(
fun resetRegistrationState() {
_registrationServerSuccess.postValue(false)
}
+
fun confirmPrepareUpload(sessionId: String, accepted: Boolean) {
PeerEventManager.resolveUserDecision(sessionId, accepted)
}
+
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("MissingPermission", "DiscouragedPrivateApi")
fun fetchCurrentNetworkInfo() {
@@ -194,9 +196,15 @@ class PeerToPeerViewModel @Inject constructor(
}
}
- fun startRegistration(ip: String, port: String, hash: String, pin: String) {
+ fun startRegistration(
+ ip: String,
+ port: String,
+ hash: String,
+ pin: String,
+ autoUpload: Boolean
+ ) {
viewModelScope.launch {
- val result = peerClient.registerPeerDevice(ip, port, hash, pin)
+ val result = peerClient.registerPeerDevice(ip, port, hash, pin, autoUpload)
result.onSuccess { sessionId ->
PeerSessionManager.saveConnectionInfo(ip, port, hash, sessionId)
// update UI state
@@ -235,6 +243,7 @@ class PeerToPeerViewModel @Inject constructor(
_registrationSuccess.postValue(true)
}
}
+
fun onUserRejectedRegistration(registrationId: String) {
//TODO when the user reject i THINK the client should go back to the
PeerEventManager.confirmRegistration(registrationId, accepted = false)
@@ -245,6 +254,7 @@ class PeerToPeerViewModel @Inject constructor(
hasNavigatedToSuccessFragment = false
}
+
fun setPeerSessionInfo(info: PeerConnectionInfo) {
_sessionInfo.value = info
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 99e265911..3c50a2d9b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -64,7 +64,8 @@ class ScanQrCodeFragment :
ip = payload.connectCode,
port = payload.port.toString(),
hash = payload.certificateHash,
- pin = payload.pin
+ pin = payload.pin,
+ autoUpload = true
)
} catch (e: Exception) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index f80d6a199..615ffab85 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -53,7 +53,8 @@ class SenderVerificationFragment :
ip = peerConnectionInfo.ip,
port = peerConnectionInfo.port,
hash = peerConnectionInfo.hash,
- pin = peerConnectionInfo.pin.toString()
+ pin = peerConnectionInfo.pin.toString(),
+ autoUpload = false
)
}
@@ -65,8 +66,6 @@ class SenderVerificationFragment :
private fun initObservers() {
-
-
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
navManager().navigateConnectManuallyVerificationFragmentToprepareUploadFragment()
From 0fcf9d08aa05c3ce27cce248889ff21d138002e8 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 1 Jul 2025 21:21:56 +0100
Subject: [PATCH 044/153] Correct ios/android connect flow
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 4 +-
.../data/peertopeer/TellaPeerToPeerServer.kt | 10 ++--
.../peertopeer/PeerConnectionPayload.kt | 4 +-
.../domain/peertopeer/PeerRegisterPayload.kt | 2 +-
.../peertopeer/PeerToPeerViewModel.kt | 7 +++
.../receipentflow/QRCodeFragment.kt | 5 +-
.../RecipientVerificationFragment.kt | 49 ++++++++++---------
.../receipentflow/ShowDeviceInfoFragment.kt | 4 +-
.../senderflow/ScanQrCodeFragment.kt | 2 +-
.../senderflow/SenderVerificationFragment.kt | 4 +-
10 files changed, 50 insertions(+), 41 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 236542047..c71fbbb77 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -72,11 +72,11 @@ class TellaPeerToPeerClient {
val payload = PeerRegisterPayload(
pin = pin,
nonce = UUID.randomUUID().toString(),
- autoUpload
+ // autoUpload
)
val jsonPayload = Json.encodeToString(payload)
- val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
+ val requestBody = jsonPayload.toRequestBody()
val client = getClientWithFingerprintValidation(expectedFingerprint)
val request = Request.Builder()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index c479a53b7..35e125aeb 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -101,11 +101,11 @@ class TellaPeerToPeerServer(
val registrationId = UUID.randomUUID().toString()
- val accepted = if (request.autoAccept) {
- true // Automatically accept
- } else {
- PeerEventManager.emitIncomingRegistrationRequest(registrationId, request)
- }
+ // val accepted = if (request.autoAccept) {
+ // true // Automatically accept
+ //} else {
+ val accepted = PeerEventManager.emitIncomingRegistrationRequest(registrationId, request)
+ //}
if (!accepted) {
call.respond(HttpStatusCode.Forbidden, "Receiver rejected the registration")
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
index 7a28595c5..c708ed611 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerConnectionPayload.kt
@@ -3,8 +3,8 @@ package org.horizontal.tella.mobile.domain.peertopeer
import com.google.gson.annotations.SerializedName
data class PeerConnectionPayload(
- @SerializedName("connect_code")
- val connectCode: String,
+ @SerializedName("ip_address")
+ val ipAddress : String,
@SerializedName("port")
val port: Int,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
index fc5f65d2b..9ae20e47e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
@@ -7,5 +7,5 @@ import java.util.UUID
data class PeerRegisterPayload(
val pin: String,
val nonce: String = UUID.randomUUID().toString(),
- val autoAccept: Boolean = false,
+ // val autoAccept: Boolean = false,
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 56913d24a..a38b7fa43 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -39,6 +39,7 @@ class PeerToPeerViewModel @Inject constructor(
peerToPeerManager: PeerToPeerManager
) : ViewModel() {
+ var isManualConnection: Boolean = true // default is manual
var hasNavigatedToSuccessFragment = false
private val _networkInfo = MutableLiveData()
val networkInfo: LiveData = _networkInfo
@@ -75,6 +76,12 @@ class PeerToPeerViewModel @Inject constructor(
viewModelScope.launch {
PeerEventManager.registrationRequests.collect { (registrationId, payload) ->
_incomingRequest.value = IncomingRegistration(registrationId, payload)
+
+ if (!isManualConnection) {
+ // QR-mode: auto-accept immediately
+ PeerEventManager.confirmRegistration(registrationId, true)
+ _registrationSuccess.postValue(true)
+ }
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 4a643d659..6be61ad9a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -43,6 +43,9 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
}
handleBack()
handleConnectManually()
+
+ viewModel.isManualConnection = false
+
viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
// Navigate to the next screen
@@ -67,7 +70,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val port = port
payload = PeerConnectionPayload(
- connectCode = ip,
+ ipAddress = ip,
port = port,
certificateHash = certHash,
pin = pin
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 67181b4be..9234e6a34 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -31,7 +31,31 @@ class RecipientVerificationFragment :
payload = Gson().fromJson(payloadJson, PeerConnectionPayload::class.java)
}
initListeners()
- initView()
+ initObservers()
+ }
+
+ private fun initListeners() {
+
+ binding.toolbar.backClickListener = {
+ peerServerStarterManager.stopServer()
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
+
+ binding.discardBtn.setOnClickListener {
+ peerServerStarterManager.stopServer()
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
+
+ binding.confirmAndConnectBtn.setOnClickListener(null)
+ }
+
+ private fun initObservers() {
+ lifecycleScope.launchWhenStarted {
+ viewModel.sessionInfo.collect { session ->
+ binding.hashContentTextView.text = session?.hash?.formatHash()
+ }
+ }
+ viewModel.isManualConnection = true
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
@@ -65,27 +89,4 @@ class RecipientVerificationFragment :
}
}
- private fun initView() {
- lifecycleScope.launchWhenStarted {
- viewModel.sessionInfo.collect { session ->
- binding.hashContentTextView.text = session?.hash?.formatHash()
- }
- }
- }
-
- private fun initListeners() {
-
- binding.toolbar.backClickListener = {
- peerServerStarterManager.stopServer()
- navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
- }
-
- binding.discardBtn.setOnClickListener {
- peerServerStarterManager.stopServer()
- navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
- }
-
- binding.confirmAndConnectBtn.setOnClickListener(null)
- }
-
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 60937962a..559e8872e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -30,7 +30,7 @@ class ShowDeviceInfoFragment :
}
private fun initView() {
- binding.connectCode.setRightText(payload?.connectCode)
+ binding.connectCode.setRightText(payload?.ipAddress)
binding.pin.setRightText(payload?.pin)
binding.port.setRightText(payload?.port.toString())
}
@@ -45,7 +45,7 @@ class ShowDeviceInfoFragment :
viewModel.clientHash.collect { hash ->
viewModel.setPeerSessionInfo(
PeerConnectionInfo(
- ip = payload?.connectCode.toString(),
+ ip = payload?.ipAddress.toString(),
port = payload?.port.toString(),
pin = payload?.pin?.toInt()!!,
hash = hash
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 3c50a2d9b..7a8687cbe 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -61,7 +61,7 @@ class ScanQrCodeFragment :
val payload = Gson().fromJson(qrContent, PeerConnectionPayload::class.java)
viewModel.startRegistration(
- ip = payload.connectCode,
+ ip = payload.ipAddress,
port = payload.port.toString(),
hash = payload.certificateHash,
pin = payload.pin,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 615ffab85..c243bb344 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -3,10 +3,7 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
@@ -65,6 +62,7 @@ class SenderVerificationFragment :
private fun initObservers() {
+ viewModel.isManualConnection = true
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
From fa439ca9e6b07acbd4d3c8eabf32652d9a15468d Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 2 Jul 2025 14:06:14 +0100
Subject: [PATCH 045/153] refactor code save sessionId
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 35 +++++++----------
.../data/peertopeer/TellaPeerToPeerServer.kt | 24 ++++++------
.../peertopeer/remote/PrepareUploadResult.kt | 13 +++++++
.../fragment/peertopeer/SenderViewModel.kt | 39 +++++++++++++------
4 files changed, 67 insertions(+), 44 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index c71fbbb77..fadf69ed2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -12,6 +12,7 @@ import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.json.JSONObject
@@ -125,7 +126,7 @@ class TellaPeerToPeerClient {
title: String,
files: List,
sessionId: String
- ): Result = withContext(Dispatchers.IO) {
+ ): PrepareUploadResult = withContext(Dispatchers.IO) {
val url = "https://$ip:$port/api/v1/prepare-upload"
val fileItems = files.map {
@@ -150,41 +151,31 @@ class TellaPeerToPeerClient {
.addHeader("Content-Type", "application/json")
.build()
- return@withContext client.newCall(request).execute().use { response ->
+ client.newCall(request).execute().use { response ->
val body = response.body?.string()
if (response.isSuccessful && body != null) {
- try {
+ return@withContext try {
val transmissionId = JSONObject(body).getString("transmissionId")
- Result.success(transmissionId)
+ PrepareUploadResult.Success(transmissionId)
} catch (e: Exception) {
Log.e("PrepareUpload", "Invalid JSON response: $body", e)
- Result.failure(Exception("Malformed server response"))
+ PrepareUploadResult.Failure(Exception("Malformed server response"))
}
} else {
Log.e("PrepareUpload", "Server error ${response.code}: ${response.message}")
- when (response.code) {
- 400 -> Log.e(
- "PrepareUpload",
- "Bad Request – likely missing or invalid fields."
- )
-
- 403 -> Log.e(
- "PrepareUpload",
- "Forbidden – the server is refusing the request."
- )
-
- 409 -> Log.e("PrepareUpload", "Conflict – maybe another active session.")
- 500 -> Log.e("PrepareUpload", "Internal Server Error – try again later.")
- else -> Log.e("PrepareUpload", "Unhandled server error code.")
+ return@withContext when (response.code) {
+ 400 -> PrepareUploadResult.BadRequest
+ 403 -> PrepareUploadResult.Forbidden
+ 409 -> PrepareUploadResult.Conflict
+ 500 -> PrepareUploadResult.ServerError
+ else -> PrepareUploadResult.Failure(Exception("Unhandled server error ${response.code}"))
}
- Result.failure(Exception("Server returned error ${response.code}"))
}
}
-
} catch (e: Exception) {
Log.e("PrepareUpload", "Exception during upload: ${e.message}", e)
- Result.failure(e)
+ PrepareUploadResult.Failure(e)
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 35e125aeb..dddd6a4ba 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -42,9 +42,9 @@ class TellaPeerToPeerServer(
private val keyPair: KeyPair,
private val certificate: X509Certificate,
private val keyStoreConfig: KeyStoreConfig,
- private val peerToPeerManager: PeerToPeerManager
+ private val peerToPeerManager: PeerToPeerManager,
) : TellaServer {
-
+ private var serverSession: PeerResponse? = null
private var engine: ApplicationEngine? = null
override val certificatePem: String
@@ -99,12 +99,15 @@ class TellaPeerToPeerServer(
return@post
}
- val registrationId = UUID.randomUUID().toString()
+ val sessionId = UUID.randomUUID().toString()
+ val session = PeerResponse(sessionId)
+ // Store the session in a shared serverSession variable
+ serverSession = session
// val accepted = if (request.autoAccept) {
// true // Automatically accept
//} else {
- val accepted = PeerEventManager.emitIncomingRegistrationRequest(registrationId, request)
+ val accepted = PeerEventManager.emitIncomingRegistrationRequest(sessionId, request)
//}
if (!accepted) {
@@ -115,8 +118,7 @@ class TellaPeerToPeerServer(
launch {
PeerEventManager.emitRegistrationSuccess()
}
-
- call.respond(HttpStatusCode.OK, PeerResponse(registrationId))
+ call.respond(HttpStatusCode.OK, session)
}
post("/api/v1/prepare-upload") {
@@ -132,6 +134,11 @@ class TellaPeerToPeerServer(
return@post
}
+ if (request.sessionId != serverSession?.sessionId) {
+ call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
+ return@post
+ }
+
val accepted = PeerEventManager.emitPrepareUploadRequest(request)
if (accepted) {
@@ -143,11 +150,6 @@ class TellaPeerToPeerServer(
} else {
call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
}
-// val transmissionId = UUID.randomUUID().toString()
-// call.respond(
-// HttpStatusCode.OK,
-// PeerPrepareUploadResponse(transmissionId)
-// )
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
new file mode 100644
index 000000000..6e05b56a4
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
@@ -0,0 +1,13 @@
+package org.horizontal.tella.mobile.data.peertopeer.remote
+
+/**
+ * Created by wafa on 2/7/2025.
+ */
+sealed class PrepareUploadResult {
+ data class Success(val transmissionId: String) : PrepareUploadResult()
+ object Forbidden : PrepareUploadResult()
+ object BadRequest : PrepareUploadResult()
+ object Conflict : PrepareUploadResult()
+ object ServerError : PrepareUploadResult()
+ data class Failure(val exception: Throwable) : PrepareUploadResult()
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index ba7445f7b..17879c871 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -14,6 +14,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.util.fromJsonToObjectList
@@ -71,28 +72,44 @@ class SenderViewModel @Inject constructor(
}
viewModelScope.launch {
- val result = peerClient.prepareUpload(
+ when (val result = peerClient.prepareUpload(
ip = info.ip,
port = info.port,
expectedFingerprint = info.expectedFingerprint,
title = title,
files = files,
sessionId = info.sessionId
- )
+ )) {
+ is PrepareUploadResult.Success -> {
+ Timber.d("Success: transmissionId = ${result.transmissionId}")
+ _prepareResults.postValue(PeerPrepareUploadResponse(result.transmissionId))
+ }
+
+ is PrepareUploadResult.Forbidden -> {
+ withContext(Dispatchers.Main) {
+ Timber.w("Upload rejected by receiver")
+ _prepareRejected.value = Event(true)
+ }
+ }
+
+ is PrepareUploadResult.BadRequest -> {
+ Timber.e("Bad request – possibly invalid data")
+ }
- result.onSuccess { transmissionId ->
- Timber.d("Success: transmissionId = $transmissionId")
- _prepareResults.postValue(PeerPrepareUploadResponse(transmissionId))
- }.onFailure { error ->
- // if (error.message?.contains("403") == true) {
- withContext(Dispatchers.Main) {
- _prepareRejected.value = Event(true)
+ is PrepareUploadResult.Conflict -> {
+ Timber.e("Upload conflict – another session may be active")
+ }
+
+ is PrepareUploadResult.ServerError -> {
+ Timber.e("Internal server error – try again later")
+ }
+
+ is PrepareUploadResult.Failure -> {
+ Timber.e(result.exception, "Unhandled error during upload")
}
}
}
}
-
-
}
From 9108c34523d5a9884816582b9a1c45179b14e17c Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 2 Jul 2025 16:22:49 +0100
Subject: [PATCH 046/153] Fix prepare upload (ios/Android)
---
.../tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index fadf69ed2..4c5579389 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -141,7 +141,7 @@ class TellaPeerToPeerClient {
val requestPayload = PrepareUploadRequest(title, sessionId, fileItems)
val jsonPayload = Json.encodeToString(requestPayload)
- val requestBody = jsonPayload.toRequestBody("application/json".toMediaType())
+ val requestBody = jsonPayload.toRequestBody()
val client = getClientWithFingerprintValidation(expectedFingerprint)
try {
From 0f07fe751894b57a12e251858b85ae5227fea07f Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 2 Jul 2025 17:11:51 +0100
Subject: [PATCH 047/153] add error in case adressIp is null
---
.../certificate/CertificateGenerator.kt | 25 ++++++++++---------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt
index 766bcd477..0f8dc74ca 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/certificate/CertificateGenerator.kt
@@ -22,9 +22,11 @@ object CertificateGenerator {
fun generateCertificate(
commonName: String = "Tella Android",
organization: String = "Tella",
- validityDays: Int = 365,
+ validityDays: Int = 7,
ipAddress: String
): Pair {
+ require(ipAddress.isNotBlank()) { "IP address must not be empty when generating a certificate." }
+
val keyGen = KeyPairGenerator.getInstance("RSA")
keyGen.initialize(2048)
val keyPair = keyGen.generateKeyPair()
@@ -41,18 +43,16 @@ object CertificateGenerator {
issuer, serialNumber, now, validTo, subject, keyPair.public
)
- if (ipAddress.isNotEmpty()) {
- val san = org.bouncycastle.asn1.x509.GeneralNames(
- org.bouncycastle.asn1.x509.GeneralName(
- org.bouncycastle.asn1.x509.GeneralName.iPAddress, ipAddress
- )
- )
- certBuilder.addExtension(
- org.bouncycastle.asn1.x509.Extension.subjectAlternativeName,
- false,
- san
+ val san = org.bouncycastle.asn1.x509.GeneralNames(
+ org.bouncycastle.asn1.x509.GeneralName(
+ org.bouncycastle.asn1.x509.GeneralName.iPAddress, ipAddress
)
- }
+ )
+ certBuilder.addExtension(
+ org.bouncycastle.asn1.x509.Extension.subjectAlternativeName,
+ false,
+ san
+ )
val signer = JcaContentSignerBuilder("SHA256withRSA")
.build(keyPair.private)
@@ -65,4 +65,5 @@ object CertificateGenerator {
return Pair(keyPair, certificate)
}
+
}
\ No newline at end of file
From 9e9eab457e1952827575bed12d6f0dae39e6566a Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 2 Jul 2025 19:11:19 +0100
Subject: [PATCH 048/153] get the mimeType dynamically and save the
transmissionId
---
.../tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt | 8 ++++++--
.../java/org/horizontal/tella/mobile/util/FileUtil.java | 6 +++---
.../views/fragment/peertopeer/PeerSessionManager.kt | 8 +++++++-
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 4c5579389..d0ccd0355 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -6,7 +6,6 @@ import kotlinx.serialization.encodeToString
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
-import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
@@ -15,6 +14,8 @@ import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
+import org.horizontal.tella.mobile.util.FileUtil.getMimeType
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
import org.json.JSONObject
import java.security.SecureRandom
import java.security.cert.CertificateException
@@ -130,11 +131,12 @@ class TellaPeerToPeerClient {
val url = "https://$ip:$port/api/v1/prepare-upload"
val fileItems = files.map {
+ val mimeType = getMimeType(it.name) ?: "application/octet-stream"
P2PFile(
id = it.id,
fileName = it.name,
size = it.size,
- fileType = "application/octet-stream",
+ fileType = mimeType,
sha256 = it.hash
)
}
@@ -157,6 +159,8 @@ class TellaPeerToPeerClient {
if (response.isSuccessful && body != null) {
return@withContext try {
val transmissionId = JSONObject(body).getString("transmissionId")
+ // Store it in the session manager
+ PeerSessionManager.setTransmissionId(transmissionId)
PrepareUploadResult.Success(transmissionId)
} catch (e: Exception) {
Log.e("PrepareUpload", "Invalid JSON response: $body", e)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/FileUtil.java b/mobile/src/main/java/org/horizontal/tella/mobile/util/FileUtil.java
index 80201e071..54a0c4930 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/FileUtil.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/FileUtil.java
@@ -62,9 +62,9 @@ public static String getPrimaryMime(String mimeType) {
@Nullable
public static String getMimeType(@NonNull String filename) {
- return MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- MimeTypeMap.getFileExtensionFromUrl(filename.toLowerCase())
- );
+ String extension = MimeTypeMap.getFileExtensionFromUrl(filename.toLowerCase());
+ // Return the corresponding MIME type or null if unknown
+ return extension != null ? MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) : null;
}
/* public static MediaFile.Type getMediaFileType(@NonNull String filename) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
index b5f8caa3e..94b6128af 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
@@ -10,7 +10,8 @@ data class PeerConnectionInfo(
val expectedFingerprint: String = "",
val sessionId: String = "",
val hash: String = "",
- val pin: Int = 0
+ val pin: Int = 0,
+ var transmissionId: String? = null
)
object PeerSessionManager {
@@ -29,6 +30,11 @@ object PeerSessionManager {
fun isSessionValid(): Boolean = connectionInfo != null
+ fun setTransmissionId(id: String) {
+ connectionInfo?.transmissionId = id
+ }
+
+ fun getTransmissionId(): String? = connectionInfo?.transmissionId
fun clear() {
connectionInfo = null
}
From 44e478c9c3a876eb44c4c2f93679d1bba626aa7d Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Thu, 3 Jul 2025 12:49:07 +0100
Subject: [PATCH 049/153] Improve code, unify routes api
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 28 ++++++-------------
.../data/peertopeer/TellaPeerToPeerServer.kt | 7 +++--
.../data/peertopeer/remote/PeerApiRoutes.kt | 11 ++++++++
.../peertopeer/PeerToPeerViewModel.kt | 2 +-
4 files changed, 24 insertions(+), 24 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index d0ccd0355..06aa5a9fc 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -10,6 +10,7 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
@@ -17,6 +18,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.util.FileUtil.getMimeType
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
import org.json.JSONObject
+import timber.log.Timber
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
@@ -65,9 +67,10 @@ class TellaPeerToPeerClient {
port: String,
expectedFingerprint: String,
pin: String,
- autoUpload: Boolean
): Result = withContext(Dispatchers.IO) {
- val url = "https://$ip:$port/api/v1/register"
+
+ val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.REGISTER)
+
Log.d("PeerClient", "Connecting to: $url")
try {
@@ -90,6 +93,7 @@ class TellaPeerToPeerClient {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val errorBody = response.body.string()
+ TODO("WE SHOULD USE TIMBER INSTEAD")
Log.e(
"PeerClient", """
HTTP ${response.code} Error
@@ -128,7 +132,8 @@ class TellaPeerToPeerClient {
files: List,
sessionId: String
): PrepareUploadResult = withContext(Dispatchers.IO) {
- val url = "https://$ip:$port/api/v1/prepare-upload"
+
+ val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.PREPARE_UPLOAD)
val fileItems = files.map {
val mimeType = getMimeType(it.name) ?: "application/octet-stream"
@@ -184,21 +189,4 @@ class TellaPeerToPeerClient {
}
- suspend fun fetchServerFingerprint(ip: String, port: Int): Result =
- withContext(Dispatchers.IO) {
- try {
- val socket = SSLSocketFactory.getDefault()
- .createSocket(ip, port) as SSLSocket
- socket.soTimeout = 5000
- socket.startHandshake()
-
- val cert = socket.session.peerCertificates[0] as X509Certificate
- val fingerprint = CertificateUtils.getPublicKeyHash(cert)
- Result.success(fingerprint)
- } catch (e: Exception) {
- Result.failure(e)
- }
- }
-
-
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index dddd6a4ba..8319b53d1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -22,6 +22,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
@@ -83,7 +84,7 @@ class TellaPeerToPeerServer(
call.respondText("The server is running securely over HTTPS.")
}
- post("/api/v1/ping") {
+ post(PeerApiRoutes.PING) {
val hash = CertificateUtils.getPublicKeyHash(certificate)
CoroutineScope(Dispatchers.IO).launch {
peerToPeerManager.notifyClientConnected(hash)
@@ -91,7 +92,7 @@ class TellaPeerToPeerServer(
call.respondText("pong", status = HttpStatusCode.OK)
}
- post("/api/v1/register") {
+ post(PeerApiRoutes.REGISTER) {
val request = try {
call.receive()
} catch (e: Exception) {
@@ -121,7 +122,7 @@ class TellaPeerToPeerServer(
call.respond(HttpStatusCode.OK, session)
}
- post("/api/v1/prepare-upload") {
+ post(PeerApiRoutes.PREPARE_UPLOAD) {
val request = try {
call.receive()
} catch (e: Exception) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt
new file mode 100644
index 000000000..5f8ae716b
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt
@@ -0,0 +1,11 @@
+package org.horizontal.tella.mobile.data.peertopeer.remote
+
+object PeerApiRoutes {
+ const val REGISTER = "/api/v1/register"
+ const val PREPARE_UPLOAD = "/api/v1/prepare-upload"
+ const val PING = "/api/v1/ping"
+
+ fun buildUrl(ip: String, port: String, endpoint: String): String {
+ return "https://$ip:$port$endpoint"
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index a38b7fa43..39a3b196d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -211,7 +211,7 @@ class PeerToPeerViewModel @Inject constructor(
autoUpload: Boolean
) {
viewModelScope.launch {
- val result = peerClient.registerPeerDevice(ip, port, hash, pin, autoUpload)
+ val result = peerClient.registerPeerDevice(ip, port, hash, pin)
result.onSuccess { sessionId ->
PeerSessionManager.saveConnectionInfo(ip, port, hash, sessionId)
// update UI state
From abb43c7c4087b084864e25c52ea829b45264f4c2 Mon Sep 17 00:00:00 2001
From: wafa
Date: Thu, 3 Jul 2025 15:01:00 +0100
Subject: [PATCH 050/153] unify code in TellaPeerToPeerClient
---
.../data/peertopeer/PeerToPeerConstants.kt | 13 +++++++++++
.../data/peertopeer/TellaPeerToPeerClient.kt | 23 ++++++++++---------
2 files changed, 25 insertions(+), 11 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerConstants.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerConstants.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerConstants.kt
new file mode 100644
index 000000000..6359cd70a
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/PeerToPeerConstants.kt
@@ -0,0 +1,13 @@
+package org.horizontal.tella.mobile.data.peertopeer
+
+/**
+ * Created by wafa on 3/7/2025.
+ */
+object PeerToPeerConstants {
+ const val TRANSMISSION_ID_KEY = "transmissionId"
+ const val CONTENT_TYPE_JSON = "application/json"
+ const val CONTENT_TYPE = "Content-Type"
+ const val CONTENT_TYPE_OCTET = "application/octet-stream"
+
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 06aa5a9fc..fa67a93a5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -2,14 +2,17 @@ package org.horizontal.tella.mobile.data.peertopeer
import android.util.Log
import com.hzontal.tella_vault.VaultFile
-import kotlinx.serialization.encodeToString
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
+import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.horizontal.tella.mobile.certificate.CertificateUtils
+import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE
+import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_JSON
+import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_OCTET
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
@@ -18,15 +21,12 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.util.FileUtil.getMimeType
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
import org.json.JSONObject
-import timber.log.Timber
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.UUID
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
-import javax.net.ssl.SSLSocket
-import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
@@ -77,7 +77,7 @@ class TellaPeerToPeerClient {
val payload = PeerRegisterPayload(
pin = pin,
nonce = UUID.randomUUID().toString(),
- // autoUpload
+ // autoUpload
)
val jsonPayload = Json.encodeToString(payload)
@@ -87,7 +87,7 @@ class TellaPeerToPeerClient {
val request = Request.Builder()
.url(url)
.post(requestBody)
- .addHeader("Content-Type", "application/json")
+ .addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON)
.build()
client.newCall(request).execute().use { response ->
@@ -105,8 +105,8 @@ class TellaPeerToPeerClient {
return@use Result.failure(Exception("HTTP ${response.code}: $errorBody"))
}
- val contentType = response.header("Content-Type") ?: ""
- if (!contentType.contains("application/json")) {
+ val contentType = response.header(CONTENT_TYPE) ?: ""
+ if (!contentType.contains(CONTENT_TYPE_JSON)) {
Log.w("PeerClient", "Unexpected Content-Type: $contentType")
}
@@ -136,7 +136,7 @@ class TellaPeerToPeerClient {
val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.PREPARE_UPLOAD)
val fileItems = files.map {
- val mimeType = getMimeType(it.name) ?: "application/octet-stream"
+ val mimeType = getMimeType(it.name) ?: CONTENT_TYPE_OCTET
P2PFile(
id = it.id,
fileName = it.name,
@@ -155,7 +155,7 @@ class TellaPeerToPeerClient {
val request = Request.Builder()
.url(url)
.post(requestBody)
- .addHeader("Content-Type", "application/json")
+ .addHeader(PeerToPeerConstants.CONTENT_TYPE, PeerToPeerConstants.CONTENT_TYPE_JSON)
.build()
client.newCall(request).execute().use { response ->
@@ -163,7 +163,8 @@ class TellaPeerToPeerClient {
if (response.isSuccessful && body != null) {
return@withContext try {
- val transmissionId = JSONObject(body).getString("transmissionId")
+ val transmissionId =
+ JSONObject(body).getString(PeerToPeerConstants.TRANSMISSION_ID_KEY)
// Store it in the session manager
PeerSessionManager.setTransmissionId(transmissionId)
PrepareUploadResult.Success(transmissionId)
From fdfae55d6959f19957d3de82230891b09631f037 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Thu, 3 Jul 2025 16:51:35 +0100
Subject: [PATCH 051/153] Fix wifi integration
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 12 +-
.../tella/mobile/util/ConnectionType.kt | 144 ++++++++++++++++++
.../peertopeer/PeerToPeerViewModel.kt | 133 ++--------------
.../peertopeer/data/ConnectionType.kt | 5 -
.../fragment/peertopeer/data/NetWorkInfo.kt | 8 -
.../receipentflow/ConnectHotspotFragment.kt | 72 +++++++--
.../senderflow/ScanQrCodeFragment.kt | 5 +-
.../senderflow/SenderVerificationFragment.kt | 3 +-
8 files changed, 225 insertions(+), 157 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/util/ConnectionType.kt
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 8319b53d1..74342bee6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -105,14 +105,18 @@ class TellaPeerToPeerServer(
// Store the session in a shared serverSession variable
serverSession = session
- // val accepted = if (request.autoAccept) {
- // true // Automatically accept
+ // val accepted = if (request.autoAccept) {
+ // true // Automatically accept
//} else {
- val accepted = PeerEventManager.emitIncomingRegistrationRequest(sessionId, request)
+ val accepted =
+ PeerEventManager.emitIncomingRegistrationRequest(sessionId, request)
//}
if (!accepted) {
- call.respond(HttpStatusCode.Forbidden, "Receiver rejected the registration")
+ call.respond(
+ HttpStatusCode.Forbidden,
+ "Receiver rejected the registration"
+ )
return@post
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/ConnectionType.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/ConnectionType.kt
new file mode 100644
index 000000000..411da5c58
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/ConnectionType.kt
@@ -0,0 +1,144 @@
+package org.horizontal.tella.mobile.util
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import android.net.wifi.WifiManager
+import android.os.Build
+import android.text.format.Formatter
+import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import java.net.Inet4Address
+import java.net.NetworkInterface
+
+enum class ConnectionType {
+ WIFI, CELLULAR, HOTSPOT, NONE
+}
+
+data class NetworkInfo(
+ val connectionType: ConnectionType,
+ val ssid: String?,
+ val ipAddress: String?,
+ var port: String = "53317"
+)
+
+class NetworkInfoManager(private val context: Context) {
+
+ private val _networkInfo = MutableLiveData()
+ val networkInfo: LiveData = _networkInfo
+
+ private var currentNetworkInfo: NetworkInfo = NetworkInfo(ConnectionType.NONE, null, null)
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ @SuppressLint("MissingPermission", "DiscouragedPrivateApi")
+ fun fetchCurrentNetworkInfo() {
+ val connectivityManager =
+ ContextCompat.getSystemService(context, ConnectivityManager::class.java)
+ val network = connectivityManager?.activeNetwork
+ val capabilities = connectivityManager?.getNetworkCapabilities(network)
+
+ when {
+ capabilities == null -> {
+ _networkInfo.postValue(NetworkInfo(ConnectionType.NONE, null, null))
+ }
+
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
+ val wifiManager =
+ context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager
+
+ val wifiInfo = wifiManager?.connectionInfo
+
+ val ssid = when {
+ wifiInfo?.ssid != null && wifiInfo.ssid != WifiManager.UNKNOWN_SSID ->
+ wifiInfo.ssid.trim('"')
+
+ else -> "Unknown WiFi (check location permissions)"
+ }
+
+ val ipAddress = wifiInfo?.ipAddress?.let {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ Formatter.formatIpAddress(it)
+ } else {
+ // Provide fallback logic if needed for newer APIs
+ getLocalIpAddress()
+ }
+ }
+
+ _networkInfo.postValue(NetworkInfo(ConnectionType.WIFI, ssid, ipAddress))
+ }
+
+ isDeviceHotspotEnabled(context) -> {
+ val hotspotSSID = getDeviceHotspotSSID(context) ?: "Hotspot"
+ val hotspotIpAddress = getDeviceHotspotIpAddress()
+ _networkInfo.postValue(NetworkInfo(ConnectionType.HOTSPOT, hotspotSSID, hotspotIpAddress))
+ }
+
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
+ _networkInfo.postValue(NetworkInfo(ConnectionType.CELLULAR, null, null))
+ }
+
+ else -> {
+ _networkInfo.postValue(NetworkInfo(ConnectionType.NONE, null, null))
+ }
+ }
+
+ currentNetworkInfo = _networkInfo.value ?: NetworkInfo(ConnectionType.NONE, null, null)
+ }
+
+ private fun isDeviceHotspotEnabled(context: Context): Boolean {
+ val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ return try {
+ val method = wifiManager.javaClass.getDeclaredMethod("isWifiApEnabled")
+ method.isAccessible = true
+ method.invoke(wifiManager) as? Boolean ?: false
+ } catch (e: Exception) {
+ e.printStackTrace()
+ false
+ }
+ }
+
+ private fun getDeviceHotspotSSID(context: Context): String? {
+ val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ return try {
+ val method = wifiManager.javaClass.getDeclaredMethod("getWifiApConfiguration")
+ method.isAccessible = true
+ val config = method.invoke(wifiManager)
+ val ssidField = config?.javaClass?.getDeclaredField("SSID")
+ ssidField?.isAccessible = true
+ ssidField?.get(config) as? String
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+ }
+
+ private fun getDeviceHotspotIpAddress(): String? {
+ return try {
+ val interfaces = NetworkInterface.getNetworkInterfaces()
+ for (intf in interfaces) {
+ if (!intf.isUp || intf.isLoopback) continue
+ for (addr in intf.inetAddresses) {
+ if (!addr.isLoopbackAddress && addr is Inet4Address) {
+ return addr.hostAddress
+ }
+ }
+ }
+ null
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+ }
+
+ private fun getLocalIpAddress(): String? {
+ return try {
+ NetworkInterface.getNetworkInterfaces().toList().flatMap { it.inetAddresses.toList() }
+ .firstOrNull { !it.isLoopbackAddress && it is Inet4Address }?.hostAddress
+ } catch (e: Exception) {
+ null
+ }
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 39a3b196d..3ae59fad6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -1,15 +1,8 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer
-import android.annotation.SuppressLint
import android.content.Context
-import android.net.ConnectivityManager
-import android.net.NetworkCapabilities
-import android.net.wifi.WifiInfo
-import android.net.wifi.WifiManager
import android.os.Build
-import android.text.format.Formatter
import androidx.annotation.RequiresApi
-import androidx.core.content.ContextCompat
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
@@ -20,16 +13,14 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
-import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
-import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
-import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
-import org.horizontal.tella.mobile.views.fragment.peertopeer.data.NetworkInfo
+import org.horizontal.tella.mobile.util.NetworkInfo
+import org.horizontal.tella.mobile.util.NetworkInfoManager
import timber.log.Timber
-import java.net.Inet4Address
-import java.net.NetworkInterface
import javax.inject.Inject
@HiltViewModel
@@ -41,8 +32,6 @@ class PeerToPeerViewModel @Inject constructor(
var isManualConnection: Boolean = true // default is manual
var hasNavigatedToSuccessFragment = false
- private val _networkInfo = MutableLiveData()
- val networkInfo: LiveData = _networkInfo
var currentNetworkInfo: NetworkInfo? = null
private val _registrationSuccess = MutableLiveData()
val registrationSuccess: LiveData get() = _registrationSuccess
@@ -59,6 +48,8 @@ class PeerToPeerViewModel @Inject constructor(
val incomingPrepareRequest: MutableLiveData = _incomingPrepareRequest
private val _incomingRequest = MutableStateFlow(null)
val incomingRequest: StateFlow = _incomingRequest
+ private val networkInfoManager = NetworkInfoManager(context)
+ val networkInfo: LiveData get() = networkInfoManager.networkInfo
init {
viewModelScope.launch {
@@ -94,121 +85,17 @@ class PeerToPeerViewModel @Inject constructor(
PeerEventManager.resolveUserDecision(sessionId, accepted)
}
- @RequiresApi(Build.VERSION_CODES.M)
- @SuppressLint("MissingPermission", "DiscouragedPrivateApi")
- fun fetchCurrentNetworkInfo() {
- val connectivityManager =
- ContextCompat.getSystemService(context, ConnectivityManager::class.java)
- val network = connectivityManager?.activeNetwork
- val capabilities = connectivityManager?.getNetworkCapabilities(network)
-
- when {
- capabilities == null -> {
- _networkInfo.value = NetworkInfo(ConnectionType.NONE, null, null)
- }
-
- capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
- val wifiManager =
- context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
- val wifiInfo = wifiManager.connectionInfo
-
- val ssid =
- if (!wifiInfo.ssid.isNullOrEmpty() && wifiInfo.ssid != WifiManager.UNKNOWN_SSID) {
- wifiInfo.ssid.trim('"')
- } else {
- getWifiSsidFromCapabilities(capabilities) ?: "Hotspot"
- }
-
- val ipAddress = Formatter.formatIpAddress(wifiInfo.ipAddress)
- _networkInfo.value = NetworkInfo(ConnectionType.WIFI, ssid, ipAddress)
- }
-
- isDeviceHotspotEnabled(context) -> {
- val hotspotSSID = getDeviceHotspotSSID(context) ?: "Hotspot"
- val hotspotIpAddress = getDeviceHotspotIpAddress()
- _networkInfo.value =
- NetworkInfo(ConnectionType.HOTSPOT, hotspotSSID, hotspotIpAddress)
- }
-
- capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
- _networkInfo.value = NetworkInfo(ConnectionType.CELLULAR, null, null)
- }
-
- else -> {
- _networkInfo.value = NetworkInfo(ConnectionType.NONE, null, null)
- }
- }
-
- currentNetworkInfo = _networkInfo.value
- }
-
- @SuppressLint("DiscouragedPrivateApi")
- private fun getDeviceHotspotSSID(context: Context): String? {
- return try {
- val wifiManager =
- context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
- val method = wifiManager.javaClass.getDeclaredMethod("getWifiApConfiguration")
- method.isAccessible = true
- val wifiConfig = method.invoke(wifiManager)
- wifiConfig?.let {
- val ssidField = it.javaClass.getDeclaredField("SSID")
- ssidField.isAccessible = true
- (ssidField.get(it) as? String)?.trim('"')
- }
- } catch (e: Exception) {
- null
- }
- }
-
- @SuppressLint("DiscouragedPrivateApi")
- private fun isDeviceHotspotEnabled(context: Context): Boolean {
- return try {
- val wifiManager =
- context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
- val method = wifiManager.javaClass.getDeclaredMethod("isWifiApEnabled")
- method.isAccessible = true
- method.invoke(wifiManager) as Boolean
- } catch (e: Exception) {
- false
- }
- }
-
- private fun getWifiSsidFromCapabilities(capabilities: NetworkCapabilities): String? {
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- (capabilities.transportInfo as? WifiInfo)?.ssid?.trim('"')
- } else {
- null
- }
- }
-
- private fun getDeviceHotspotIpAddress(): String? {
- return try {
- val networkInterfaces = NetworkInterface.getNetworkInterfaces()
- networkInterfaces.iterator().forEach { networkInterface ->
- networkInterface.inetAddresses.iterator().forEach { inetAddress ->
- if (!inetAddress.isLoopbackAddress && inetAddress is Inet4Address) {
- if (networkInterface.displayName.contains("wlan") || networkInterface.displayName.contains(
- "ap"
- )
- ) {
- return inetAddress.hostAddress
- }
- }
- }
- }
- null
- } catch (e: Exception) {
- null
- }
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun updateNetworkInfo() {
+ networkInfoManager.fetchCurrentNetworkInfo()
}
fun startRegistration(
ip: String,
port: String,
hash: String,
- pin: String,
- autoUpload: Boolean
+ pin: String
) {
viewModelScope.launch {
val result = peerClient.registerPeerDevice(ip, port, hash, pin)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt
deleted file mode 100644
index 4cca5a3b9..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/ConnectionType.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer.data
-
-enum class ConnectionType {
- WIFI, CELLULAR, HOTSPOT, NONE
-}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt
deleted file mode 100644
index ffaf84136..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/data/NetWorkInfo.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer.data
-
-data class NetworkInfo(
- val type: ConnectionType,
- val networkName: String?,
- val ipAddress: String?,
- var port: String = "53317"
-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index 4331fb4fe..0ce670c43 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -1,17 +1,23 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.Manifest.permission.ACCESS_NETWORK_STATE
+import android.Manifest.permission.ACCESS_WIFI_STATE
+import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
import com.hzontal.tella_locking_ui.ui.pin.pinview.ResourceUtils.getColor
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.ConnectHotspotLayoutBinding
+import org.horizontal.tella.mobile.util.ConnectionType
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
-import org.horizontal.tella.mobile.views.fragment.peertopeer.data.ConnectionType
@AndroidEntryPoint
class ConnectHotspotFragment :
@@ -20,21 +26,35 @@ class ConnectHotspotFragment :
private val viewModel: PeerToPeerViewModel by activityViewModels()
private var isCheckboxChecked = false
+ @RequiresApi(Build.VERSION_CODES.M)
+ private val requestPermissionLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
+ val fineLocationGranted = permissions[ACCESS_FINE_LOCATION] ?: false
+ val wifiStateGranted = permissions[ACCESS_WIFI_STATE] ?: false
+ val networkStateGranted = permissions[ACCESS_NETWORK_STATE] ?: false
+
+ if (fineLocationGranted && wifiStateGranted && networkStateGranted) {
+ viewModel.updateNetworkInfo()
+ } else {
+ baseActivity.showToast("Location and network permissions are required to get WiFi SSID.")
+ }
+ }
@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initObservers()
initListeners()
- viewModel.fetchCurrentNetworkInfo()
+ checkAndRequestPermissions()
}
private fun initObservers() {
viewModel.networkInfo.observe(viewLifecycleOwner) { info ->
- when (info.type) {
+ viewModel.currentNetworkInfo = info
+ when (info.connectionType) {
ConnectionType.HOTSPOT, ConnectionType.WIFI, ConnectionType.CELLULAR -> {
- binding.currentWifiText.setRightText(info.networkName)
- updateNextButtonState(ConnectionType.HOTSPOT)
+ binding.currentWifiText.setRightText(info.ssid ?: "Unknown")
+ updateNextButtonState(info.connectionType)
}
ConnectionType.NONE -> {
@@ -46,18 +66,14 @@ class ConnectHotspotFragment :
}
private fun initListeners() {
-
binding.currentWifi.setOnCheckedChangeListener { isChecked ->
isCheckboxChecked = isChecked
- updateNextButtonState(viewModel.currentNetworkInfo?.type)
+ val currentType = viewModel.networkInfo.value?.connectionType ?: ConnectionType.NONE
+ updateNextButtonState(currentType)
}
binding.toolbar.backClickListener = { baseActivity.onBackPressed() }
-
- binding.nextBtn.setOnClickListener { }
-
binding.backBtn.setOnClickListener { baseActivity.onBackPressed() }
-
}
private fun updateNextButtonState(connectionType: ConnectionType?) {
@@ -80,4 +96,36 @@ class ConnectHotspotFragment :
navManager().navigateFromActionConnectHotspotScreenToQrCodeScreen()
}
-}
\ No newline at end of file
+ @RequiresApi(Build.VERSION_CODES.M)
+ private fun checkAndRequestPermissions() {
+ val permissionsToRequest = mutableListOf()
+
+ if (ContextCompat.checkSelfPermission(
+ baseActivity,
+ ACCESS_FINE_LOCATION
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ permissionsToRequest.add(ACCESS_FINE_LOCATION)
+ }
+ if (ContextCompat.checkSelfPermission(
+ baseActivity,
+ ACCESS_WIFI_STATE
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ permissionsToRequest.add(ACCESS_WIFI_STATE)
+ }
+ if (ContextCompat.checkSelfPermission(
+ baseActivity,
+ ACCESS_NETWORK_STATE
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ permissionsToRequest.add(ACCESS_NETWORK_STATE)
+ }
+
+ if (permissionsToRequest.isNotEmpty()) {
+ requestPermissionLauncher.launch(permissionsToRequest.toTypedArray())
+ } else {
+ viewModel.updateNetworkInfo()
+ }
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 7a8687cbe..6691a6461 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -64,8 +64,7 @@ class ScanQrCodeFragment :
ip = payload.ipAddress,
port = payload.port.toString(),
hash = payload.certificateHash,
- pin = payload.pin,
- autoUpload = true
+ pin = payload.pin
)
} catch (e: Exception) {
@@ -117,7 +116,7 @@ class ScanQrCodeFragment :
}
}
- private fun initObservers(){
+ private fun initObservers() {
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
navManager().navigateFromScanQrCodeToPrepareUploadFragment()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index c243bb344..f5b2b9dc0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -50,8 +50,7 @@ class SenderVerificationFragment :
ip = peerConnectionInfo.ip,
port = peerConnectionInfo.port,
hash = peerConnectionInfo.hash,
- pin = peerConnectionInfo.pin.toString(),
- autoUpload = false
+ pin = peerConnectionInfo.pin.toString()
)
}
From 4351bcf00a3f7bbde7ce2d03bfa39fe579bf6fdb Mon Sep 17 00:00:00 2001
From: wafa
Date: Fri, 4 Jul 2025 19:03:47 +0100
Subject: [PATCH 052/153] refactor code
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 29 +++++++------------
1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index fa67a93a5..9f5a6c71e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -1,6 +1,5 @@
package org.horizontal.tella.mobile.data.peertopeer
-import android.util.Log
import com.hzontal.tella_vault.VaultFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -21,6 +20,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.util.FileUtil.getMimeType
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
import org.json.JSONObject
+import timber.log.Timber
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
@@ -70,9 +70,7 @@ class TellaPeerToPeerClient {
): Result = withContext(Dispatchers.IO) {
val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.REGISTER)
-
- Log.d("PeerClient", "Connecting to: $url")
-
+ Timber.d("Connecting to: $url")
try {
val payload = PeerRegisterPayload(
pin = pin,
@@ -93,21 +91,14 @@ class TellaPeerToPeerClient {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val errorBody = response.body.string()
- TODO("WE SHOULD USE TIMBER INSTEAD")
- Log.e(
- "PeerClient", """
- HTTP ${response.code} Error
- URL: $url
- Headers: ${response.headers}
- Body: $errorBody
- """.trimIndent()
- )
+ Timber.e( """HTTP ${response.code} Error URL: $url Headers: ${response.headers} Body: $errorBody """.trimIndent())
return@use Result.failure(Exception("HTTP ${response.code}: $errorBody"))
}
val contentType = response.header(CONTENT_TYPE) ?: ""
if (!contentType.contains(CONTENT_TYPE_JSON)) {
- Log.w("PeerClient", "Unexpected Content-Type: $contentType")
+ Timber.e("PeerClient Unexpected Content-Type: %s", contentType)
+
}
val body = response.body?.string() ?: ""
@@ -119,7 +110,7 @@ class TellaPeerToPeerClient {
}
}
} catch (e: Exception) {
- Log.e("PeerClient", "Request failed", e)
+ Timber.e(e, "PeerClient Request failed")
Result.failure(e)
}
}
@@ -155,7 +146,7 @@ class TellaPeerToPeerClient {
val request = Request.Builder()
.url(url)
.post(requestBody)
- .addHeader(PeerToPeerConstants.CONTENT_TYPE, PeerToPeerConstants.CONTENT_TYPE_JSON)
+ .addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON)
.build()
client.newCall(request).execute().use { response ->
@@ -169,11 +160,11 @@ class TellaPeerToPeerClient {
PeerSessionManager.setTransmissionId(transmissionId)
PrepareUploadResult.Success(transmissionId)
} catch (e: Exception) {
- Log.e("PrepareUpload", "Invalid JSON response: $body", e)
+ Timber.e(e, "Invalid JSON response: %s", body)
PrepareUploadResult.Failure(Exception("Malformed server response"))
}
} else {
- Log.e("PrepareUpload", "Server error ${response.code}: ${response.message}")
+ Timber.e("Server error %d: %s", response.code, response.message)
return@withContext when (response.code) {
400 -> PrepareUploadResult.BadRequest
403 -> PrepareUploadResult.Forbidden
@@ -184,7 +175,7 @@ class TellaPeerToPeerClient {
}
}
} catch (e: Exception) {
- Log.e("PrepareUpload", "Exception during upload: ${e.message}", e)
+ Timber.e(e, "Exception during upload")
PrepareUploadResult.Failure(e)
}
}
From 25152dd721736537d26cb1451c8587f49507dee8 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Fri, 4 Jul 2025 20:06:07 +0100
Subject: [PATCH 053/153] fix audio recorder
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 5 +-
.../senderflow/PrepareUploadFragment.kt | 63 +++++++++++++------
.../views/fragment/recorder/MicActivity.kt | 9 ++-
3 files changed, 52 insertions(+), 25 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 9f5a6c71e..5ec73bb3c 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -127,7 +127,7 @@ class TellaPeerToPeerClient {
val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.PREPARE_UPLOAD)
val fileItems = files.map {
- val mimeType = getMimeType(it.name) ?: CONTENT_TYPE_OCTET
+ val mimeType = it.mimeType ?: CONTENT_TYPE_OCTET
P2PFile(
id = it.id,
fileName = it.name,
@@ -150,7 +150,7 @@ class TellaPeerToPeerClient {
.build()
client.newCall(request).execute().use { response ->
- val body = response.body?.string()
+ val body = response.body.string()
if (response.isSuccessful && body != null) {
return@withContext try {
@@ -172,6 +172,7 @@ class TellaPeerToPeerClient {
500 -> PrepareUploadResult.ServerError
else -> PrepareUploadResult.Failure(Exception("Unhandled server error ${response.code}"))
}
+
}
}
} catch (e: Exception) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index c0564ef3d..182129333 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -4,9 +4,7 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
-import android.view.Gravity
import android.view.View
-import android.widget.Toast
import androidx.fragment.app.setFragmentResultListener
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
@@ -16,14 +14,16 @@ import com.hzontal.tella_locking_ui.common.extensions.onChange
import com.hzontal.tella_vault.VaultFile
import com.hzontal.tella_vault.filter.FilterType
import dagger.hilt.android.AndroidEntryPoint
+import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.bus.EventObserver
+import org.horizontal.tella.mobile.bus.event.AudioRecordEvent
import org.horizontal.tella.mobile.databinding.FragmentPrepareUploadBinding
import org.horizontal.tella.mobile.domain.entity.reports.ReportInstance
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.C
import org.horizontal.tella.mobile.views.activity.camera.CameraActivity
import org.horizontal.tella.mobile.views.activity.camera.CameraActivity.Companion.CAPTURE_WITH_AUTO_UPLOAD
-import org.horizontal.tella.mobile.views.activity.viewer.sharedViewModel
import org.horizontal.tella.mobile.views.adapters.reports.ReportsFilesRecyclerViewAdapter
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_AUDIO
@@ -31,6 +31,7 @@ import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_RE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_VAULT_FILE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.OnNavBckListener
import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
+import org.horizontal.tella.mobile.views.fragment.recorder.MicActivity
import org.horizontal.tella.mobile.views.fragment.recorder.REPORT_ENTRY
import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.AttachmentsActivitySelector
import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.VAULT_FILES_FILTER
@@ -42,6 +43,8 @@ import org.hzontal.shared_ui.bottomsheet.VaultSheetUtils.IVaultFilesSelector
import org.hzontal.shared_ui.bottomsheet.VaultSheetUtils.showVaultSelectFilesSheet
import org.hzontal.shared_ui.utils.DialogUtils
+var PREPARE_UPLOAD_ENTRY = "PREPARE_UPLOAD_ENTRY"
+
@AndroidEntryPoint
class PrepareUploadFragment :
BaseBindingFragment(FragmentPrepareUploadBinding::inflate),
@@ -51,6 +54,8 @@ class PrepareUploadFragment :
private var reportInstance: ReportInstance? = null
private val viewModel: SenderViewModel by viewModels()
private var isNewDraft = true
+ private var disposables =
+ MyApplication.bus().createCompositeDisposable()
private val filesRecyclerViewAdapter: ReportsFilesRecyclerViewAdapter by lazy {
ReportsFilesRecyclerViewAdapter(this)
@@ -68,6 +73,7 @@ class PrepareUploadFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
initView()
initData()
+ onAudioRecordingListener()
}
private fun initView() {
@@ -108,30 +114,31 @@ class PrepareUploadFragment :
}
viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
- val id = response.transmissionId
+ val id = response.transmissionId
DialogUtils.showBottomMessage(
baseActivity,
getString(R.string.the_receiver_accepted_the_files_transfer),
false,
3000
)
- // navigate to next screen
+ // navigate to next screen
}
- binding.toolbar.backClickListener = { BottomSheetUtils.showConfirmSheet(
- baseActivity.supportFragmentManager,
- getString((R.string.exit_nearby_sharing)),
- getString(R.string.your_progress_will_be_lost),
- getString(R.string.action_exit),
- getString(R.string.action_cancel),
- object : BottomSheetUtils.ActionConfirmed {
- override fun accept(isConfirmed: Boolean) {
- if (isConfirmed) {
- findNavController().popBackStack()
+ binding.toolbar.backClickListener = {
+ BottomSheetUtils.showConfirmSheet(
+ baseActivity.supportFragmentManager,
+ getString((R.string.exit_nearby_sharing)),
+ getString(R.string.your_progress_will_be_lost),
+ getString(R.string.action_exit),
+ getString(R.string.action_cancel),
+ object : BottomSheetUtils.ActionConfirmed {
+ override fun accept(isConfirmed: Boolean) {
+ if (isConfirmed) {
+ findNavController().popBackStack()
+ }
}
}
- }
- )
+ )
}
highLightButtonsInit()
checkIsNewDraftEntry()
@@ -146,7 +153,6 @@ class PrepareUploadFragment :
}
-
private fun highLightButtonsInit() {
binding.apply {
reportTitleEt.let { title ->
@@ -245,6 +251,9 @@ class PrepareUploadFragment :
} catch (e: java.lang.Exception) {
FirebaseCrashlytics.getInstance().recordException(e)
}
+ val intent = Intent(activity, MicActivity::class.java)
+ intent.putExtra(PREPARE_UPLOAD_ENTRY, true)
+ baseActivity.startActivity(intent)
}
@Deprecated("Deprecated in Java")
@@ -271,7 +280,7 @@ class PrepareUploadFragment :
private fun highLightButtons() {
val isSubmitEnabled =
- isTitleEnabled && filesRecyclerViewAdapter.getFiles()
+ isTitleEnabled && filesRecyclerViewAdapter.getFiles()
.isNotEmpty()
val disabled: Float = context?.getString(R.string.alpha_disabled)?.toFloat() ?: 1.0f
@@ -289,7 +298,10 @@ class PrepareUploadFragment :
if (isSubmitEnabled) {
val selectedFiles = filesRecyclerViewAdapter.getFiles()
if (selectedFiles.isNotEmpty()) {
- bundle.putSerializable("selectedFiles", ArrayList(selectedFiles)) // assuming VaultFile is Serializable
+ bundle.putSerializable(
+ "selectedFiles",
+ ArrayList(selectedFiles)
+ ) // assuming VaultFile is Serializable
// navigate to waiting view
navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
} else {
@@ -301,6 +313,7 @@ class PrepareUploadFragment :
}
}
}
+
private fun showSubmitReportErrorSnackBar() {
val errorRes = R.string.Snackbar_Submit_Files_Error
@@ -323,4 +336,14 @@ class PrepareUploadFragment :
return true
}
+ private fun onAudioRecordingListener() {
+ disposables.wire(
+ AudioRecordEvent::class.java,
+ object : EventObserver() {
+ override fun onNext(event: AudioRecordEvent) {
+ putFiles(listOf(event.vaultFile))
+ }
+ })
+ }
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/recorder/MicActivity.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/recorder/MicActivity.kt
index dc4b2e3b1..ce3dcc687 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/recorder/MicActivity.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/recorder/MicActivity.kt
@@ -33,6 +33,7 @@ import org.horizontal.tella.mobile.views.activity.MetadataActivity
import org.horizontal.tella.mobile.views.activity.camera.CameraActivity.Companion.VAULT_CURRENT_ROOT_PARENT
import org.horizontal.tella.mobile.views.activity.viewer.toolBar
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_VAULT_FILE
+import org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow.PREPARE_UPLOAD_ENTRY
import org.horizontal.tella.mobile.views.interfaces.VerificationWorkStatusCallback
import java.util.Locale
import java.util.UUID
@@ -44,6 +45,7 @@ class MicActivity : MetadataActivity(),
private var animator: ObjectAnimator? = null
private var isCollect: Boolean = false
private var isReport: Boolean = false
+ private var isPrepareUpload = false
private var notRecording = false
private var lastUpdateTime: Long = 0
private var isAddingInProgress = false
@@ -75,6 +77,7 @@ class MicActivity : MetadataActivity(),
if (intent != null) {
isCollect = intent.getBooleanExtra(COLLECT_ENTRY, false)
isReport = intent.getBooleanExtra(REPORT_ENTRY, false)
+ isPrepareUpload = intent.getBooleanExtra(PREPARE_UPLOAD_ENTRY, false)
currentRootParent = intent.getStringExtra(VAULT_CURRENT_ROOT_PARENT)
}
@@ -93,11 +96,11 @@ class MicActivity : MetadataActivity(),
recordingName = findViewById(R.id.rec_name)
toolBar = findViewById(R.id.toolbar)
- if (isCollect || isReport || currentRootParent?.isNotEmpty() == true) {
+ if (isCollect || isReport || isPrepareUpload || currentRootParent?.isNotEmpty() == true) {
mPlay.visibility = View.GONE
}
- if (isCollect || currentRootParent?.isNotEmpty() == true) {
+ if (isCollect || isPrepareUpload || currentRootParent?.isNotEmpty() == true) {
toolBar.navigationIcon =
ContextCompat.getDrawable(this, R.drawable.ic_close_white)
@@ -304,7 +307,7 @@ class MicActivity : MetadataActivity(),
}
private fun maybeReturnCollectRecording(vaultFile: VaultFile?) {
- if (isCollect) {
+ if (isCollect || isPrepareUpload) {
MyApplication.bus().post(AudioRecordEvent(vaultFile))
}
if (isReport) {
From 9dc0e97b374fb6c33fea3570e8f644962d8ce834 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Fri, 4 Jul 2025 21:17:22 +0100
Subject: [PATCH 054/153] WIP unify code
---
.../tella/mobile/MyApplication.java | 3 ++
.../data/peertopeer/TellaPeerToPeerClient.kt | 49 +++++++++++--------
.../data/peertopeer/TellaPeerToPeerServer.kt | 38 +++++++++++---
.../managers/PeerServerStarterManager.kt | 9 +++-
.../peertopeer/remote/PrepareUploadResult.kt | 8 +--
.../peertopeer/remote/RegisterPeerResult.kt | 12 +++++
.../peertopeer/PeerEventManager.kt | 3 +-
.../fragment/peertopeer => util}/Event.kt | 2 +-
.../peertopeer/PeerToPeerViewModel.kt | 43 +++++++++++++---
.../fragment/peertopeer/SenderViewModel.kt | 5 +-
.../receipentflow/QRCodeFragment.kt | 8 +--
.../WaitingReceiverFragment.kt | 3 +-
.../{ => senderflow}/WaitingSenderFragment.kt | 3 +-
.../res/navigation/peer_to_peer_graph.xml | 4 +-
14 files changed, 137 insertions(+), 53 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/RegisterPeerResult.kt
rename mobile/src/main/java/org/horizontal/tella/mobile/{views/fragment => domain}/peertopeer/PeerEventManager.kt (93%)
rename mobile/src/main/java/org/horizontal/tella/mobile/{views/fragment/peertopeer => util}/Event.kt (87%)
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/{ => receipentflow}/WaitingReceiverFragment.kt (93%)
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/{ => senderflow}/WaitingSenderFragment.kt (91%)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java b/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java
index 4204f9020..1ca39ffd3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/MyApplication.java
@@ -8,6 +8,7 @@
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.net.http.HttpResponseCache;
import android.os.Build;
import android.os.StrictMode;
import android.os.Bundle;
@@ -20,6 +21,7 @@
import androidx.appcompat.app.AppCompatDelegate;
import androidx.hilt.work.HiltWorkerFactory;
import androidx.lifecycle.ProcessLifecycleOwner;
+import androidx.multidex.MultiDex;
import androidx.multidex.MultiDexApplication;
import androidx.work.Configuration;
@@ -169,6 +171,7 @@ public static void resetKeys() {
@Override
protected void attachBaseContext(Context newBase) {
+ MultiDex.install(this);
CommonPrefs.getInstance().init(newBase);
SharedPrefs.getInstance().init(newBase);
super.attachBaseContext(LocaleManager.getInstance().getLocalizedContext(newBase));
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 5ec73bb3c..186d1b23a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -5,6 +5,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
+import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
@@ -15,9 +16,9 @@ import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_T
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
+import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
-import org.horizontal.tella.mobile.util.FileUtil.getMimeType
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
import org.json.JSONObject
import timber.log.Timber
@@ -67,21 +68,22 @@ class TellaPeerToPeerClient {
port: String,
expectedFingerprint: String,
pin: String,
- ): Result = withContext(Dispatchers.IO) {
+ ): RegisterPeerResult = withContext(Dispatchers.IO) {
val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.REGISTER)
Timber.d("Connecting to: $url")
+
try {
val payload = PeerRegisterPayload(
pin = pin,
- nonce = UUID.randomUUID().toString(),
- // autoUpload
+ nonce = UUID.randomUUID().toString()
)
val jsonPayload = Json.encodeToString(payload)
val requestBody = jsonPayload.toRequestBody()
val client = getClientWithFingerprintValidation(expectedFingerprint)
+
val request = Request.Builder()
.url(url)
.post(requestBody)
@@ -89,32 +91,37 @@ class TellaPeerToPeerClient {
.build()
client.newCall(request).execute().use { response ->
- if (!response.isSuccessful) {
- val errorBody = response.body.string()
- Timber.e( """HTTP ${response.code} Error URL: $url Headers: ${response.headers} Body: $errorBody """.trimIndent())
- return@use Result.failure(Exception("HTTP ${response.code}: $errorBody"))
- }
-
- val contentType = response.header(CONTENT_TYPE) ?: ""
- if (!contentType.contains(CONTENT_TYPE_JSON)) {
- Timber.e("PeerClient Unexpected Content-Type: %s", contentType)
+ val body = response.body?.string().orEmpty()
+ if (response.isSuccessful) {
+ return@use try {
+ val json = JSONObject(body)
+ val sessionId = json.getString("sessionId")
+ RegisterPeerResult.Success(sessionId)
+ } catch (e: Exception) {
+ RegisterPeerResult.Failure(Exception("Malformed JSON: ${e.message}"))
+ }
}
- val body = response.body?.string() ?: ""
- return@use try {
- val json = JSONObject(body)
- Result.success(json.getString("sessionId"))
- } catch (e: Exception) {
- Result.failure(Exception("Invalid JSON response: ${e.message}"))
+ // Handle known status codes
+ return@use when (response.code) {
+ 400 -> RegisterPeerResult.InvalidFormat
+ 401 -> RegisterPeerResult.InvalidPin
+ 403 -> RegisterPeerResult.RejectedByReceiver
+ 409 -> RegisterPeerResult.Conflict
+ 429 -> RegisterPeerResult.TooManyRequests
+ 500 -> RegisterPeerResult.ServerError
+ else -> RegisterPeerResult.Failure(Exception("Unhandled error ${response.code}: $body"))
}
}
+
} catch (e: Exception) {
- Timber.e(e, "PeerClient Request failed")
- Result.failure(e)
+ Timber.e(e, "registerPeerDevice failed")
+ return@withContext RegisterPeerResult.Failure(e)
}
}
+
suspend fun prepareUpload(
ip: String,
port: String,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 74342bee6..5d1e5cdd5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -29,7 +29,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.domain.peertopeer.PeerResponse
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerEventManager
+import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
@@ -40,6 +40,7 @@ const val port = 53317
class TellaPeerToPeerServer(
private val ip: String,
private val serverPort: Int = port,
+ private val pin: Int,
private val keyPair: KeyPair,
private val certificate: X509Certificate,
private val keyStoreConfig: KeyStoreConfig,
@@ -96,21 +97,36 @@ class TellaPeerToPeerServer(
val request = try {
call.receive()
} catch (e: Exception) {
- call.respond(HttpStatusCode.BadRequest, "Invalid request body")
+ call.respond(HttpStatusCode.BadRequest, "Invalid request format")
return@post
}
+ //TODO CHECK IF THE PIN IS CORRECT
+ if (!isValidPin(request.pin) || pin.toString() != request.pin) {
+ call.respond(HttpStatusCode.Unauthorized, "Invalid PIN")
+ return@post
+ }
+
+ if (serverSession != null) {
+ call.respond(HttpStatusCode.Conflict, "Active session already exists")
+ return@post
+ }
+
+ // if (isRateLimited(...)) {
+ // call.respond(HttpStatusCode.TooManyRequests, "Too many requests")
+ // return@post
+ // }
+
val sessionId = UUID.randomUUID().toString()
val session = PeerResponse(sessionId)
- // Store the session in a shared serverSession variable
serverSession = session
- // val accepted = if (request.autoAccept) {
- // true // Automatically accept
- //} else {
- val accepted =
+ val accepted = try {
PeerEventManager.emitIncomingRegistrationRequest(sessionId, request)
- //}
+ } catch (e: Exception) {
+ call.respond(HttpStatusCode.InternalServerError, "Internal error")
+ return@post
+ }
if (!accepted) {
call.respond(
@@ -123,9 +139,11 @@ class TellaPeerToPeerServer(
launch {
PeerEventManager.emitRegistrationSuccess()
}
+
call.respond(HttpStatusCode.OK, session)
}
+
post(PeerApiRoutes.PREPARE_UPLOAD) {
val request = try {
call.receive()
@@ -165,4 +183,8 @@ class TellaPeerToPeerServer(
override fun stop() {
engine?.stop(1000, 5000)
}
+
+ private fun isValidPin(pin: String): Boolean {
+ return pin.length == 6 // or whatever your rule is
+ }
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
index 046ac8e5a..d396f078a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
@@ -16,11 +16,18 @@ class PeerServerStarterManager @Inject constructor(
) {
private var server: TellaPeerToPeerServer? = null
- fun startServer(ip: String, keyPair: KeyPair, cert: X509Certificate, config: KeyStoreConfig) {
+ fun startServer(
+ ip: String,
+ keyPair: KeyPair,
+ pin: Int,
+ cert: X509Certificate,
+ config: KeyStoreConfig
+ ) {
if (server == null) {
server = TellaPeerToPeerServer(
ip = ip,
keyPair = keyPair,
+ pin = pin,
certificate = cert,
keyStoreConfig = config,
peerToPeerManager = peerToPeerManager
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
index 6e05b56a4..3aa161221 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
@@ -5,9 +5,9 @@ package org.horizontal.tella.mobile.data.peertopeer.remote
*/
sealed class PrepareUploadResult {
data class Success(val transmissionId: String) : PrepareUploadResult()
- object Forbidden : PrepareUploadResult()
- object BadRequest : PrepareUploadResult()
- object Conflict : PrepareUploadResult()
- object ServerError : PrepareUploadResult()
+ data object Forbidden : PrepareUploadResult()
+ data object BadRequest : PrepareUploadResult()
+ data object Conflict : PrepareUploadResult()
+ data object ServerError : PrepareUploadResult()
data class Failure(val exception: Throwable) : PrepareUploadResult()
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/RegisterPeerResult.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/RegisterPeerResult.kt
new file mode 100644
index 000000000..204056f2f
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/RegisterPeerResult.kt
@@ -0,0 +1,12 @@
+package org.horizontal.tella.mobile.data.peertopeer.remote
+
+sealed class RegisterPeerResult {
+ data class Success(val sessionId: String) : RegisterPeerResult()
+ data object InvalidFormat : RegisterPeerResult() // 400
+ data object InvalidPin : RegisterPeerResult() // 401
+ data object Conflict : RegisterPeerResult() // 409
+ data object TooManyRequests : RegisterPeerResult() // 429
+ data object ServerError : RegisterPeerResult() // 500
+ data object RejectedByReceiver : RegisterPeerResult() // 403
+ data class Failure(val exception: Throwable) : RegisterPeerResult()
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
similarity index 93%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
index 5b4da64b0..4f24426a5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerEventManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
@@ -1,10 +1,9 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer
+package org.horizontal.tella.mobile.domain.peertopeer
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
-import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
/**
* Created by wafa on 3/6/2025.
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/Event.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/Event.kt
similarity index 87%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/Event.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/util/Event.kt
index 17f216dde..d3649b743 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/Event.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/Event.kt
@@ -1,4 +1,4 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer
+package org.horizontal.tella.mobile.util
/**
* Created by wafa on 23/6/2025.
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 3ae59fad6..1fd34f1ce 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -17,7 +17,9 @@ import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
+import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
+import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
import timber.log.Timber
@@ -98,18 +100,45 @@ class PeerToPeerViewModel @Inject constructor(
pin: String
) {
viewModelScope.launch {
- val result = peerClient.registerPeerDevice(ip, port, hash, pin)
- result.onSuccess { sessionId ->
- PeerSessionManager.saveConnectionInfo(ip, port, hash, sessionId)
- // update UI state
- _registrationSuccess.postValue(true)
- }.onFailure { error ->
- Timber.d("error ***** $error")
+ when (val result = peerClient.registerPeerDevice(ip, port, hash, pin)) {
+ is RegisterPeerResult.Success -> {
+ PeerSessionManager.saveConnectionInfo(ip, port, hash, result.sessionId)
+ _registrationSuccess.postValue(true)
+ }
+
+ RegisterPeerResult.InvalidPin -> {
+ _getHashError.postValue(Exception("Invalid PIN"))
+ }
+
+ RegisterPeerResult.InvalidFormat -> {
+ _getHashError.postValue(Exception("Invalid request format"))
+ }
+
+ RegisterPeerResult.Conflict -> {
+ _getHashError.postValue(Exception("Active session already exists"))
+ }
+
+ RegisterPeerResult.TooManyRequests -> {
+ _getHashError.postValue(Exception("Too many requests, try again later"))
+ }
+
+ RegisterPeerResult.ServerError -> {
+ _getHashError.postValue(Exception("Server error, try again later"))
+ }
+ RegisterPeerResult.RejectedByReceiver -> {
+ _getHashError.postValue(Exception("Receiver rejected the registration"))
+ }
+
+ is RegisterPeerResult.Failure -> {
+ Timber.e(result.exception, "Registration failed")
+ _getHashError.postValue(result.exception)
+ }
}
}
}
+
fun handleCertificate(ip: String, port: String, pin: String) {
viewModelScope.launch {
val result = FingerprintFetcher.fetch(ip, port.toInt())
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 17879c871..e78e013ae 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -17,6 +17,7 @@ import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
+import org.horizontal.tella.mobile.util.Event
import org.horizontal.tella.mobile.util.fromJsonToObjectList
import timber.log.Timber
import javax.inject.Inject
@@ -46,8 +47,8 @@ class SenderViewModel @Inject constructor(
.subscribeOn(Schedulers.io())
.onErrorReturn { null } // safe, allows null
}
- .filter { it != null } // filter out nulls
- .map { it!! } // safe to force unwrap if you're sure it's not null now
+ .filter { true } // filter out nulls
+ .map { it } // safe to force unwrap if you're sure it's not null now
.toList()
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 6be61ad9a..7f75ac6f6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -63,17 +63,19 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val (keyPair, certificate) = CertificateGenerator.generateCertificate(ipAddress = ip)
val config = KeyStoreConfig()
- peerServerStarterManager.startServer(ip, keyPair, certificate, config)
val certHash = CertificateUtils.getPublicKeyHash(certificate)
- val pin = (100000..999999).random().toString()
+ val pin = (100000..999999).random()
val port = port
+ peerServerStarterManager.startServer(ip, keyPair, pin, certificate, config)
+
+
payload = PeerConnectionPayload(
ipAddress = ip,
port = port,
certificateHash = certHash,
- pin = pin
+ pin = pin.toString()
)
qrPayload = Gson().toJson(payload)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
similarity index 93%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
index 67f98f5d2..990714528 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingReceiverFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
@@ -1,4 +1,4 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
@@ -7,6 +7,7 @@ import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
import org.hzontal.shared_ui.utils.DialogUtils
/**
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingSenderFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
similarity index 91%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingSenderFragment.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
index 5a3bc4340..6570e8100 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/WaitingSenderFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
@@ -1,4 +1,4 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
import android.os.Bundle
import android.view.View
@@ -8,6 +8,7 @@ import com.hzontal.tella_vault.VaultFile
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
/**
* Created by wafa on 3/6/2025.
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index effc7eff2..a68756270 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -109,7 +109,7 @@
From d2557e2e853c04342f2ba48cad29a5c2c0216f09 Mon Sep 17 00:00:00 2001
From: wafa
Date: Mon, 7 Jul 2025 13:09:24 +0100
Subject: [PATCH 055/153] refactor code
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 115 +++++++++---------
1 file changed, 60 insertions(+), 55 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 186d1b23a..3fda5b503 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -5,7 +5,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
-import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
@@ -55,12 +54,9 @@ class TellaPeerToPeerClient {
init(null, arrayOf(trustManager), SecureRandom())
}
- return OkHttpClient.Builder()
- .connectTimeout(30, TimeUnit.SECONDS)
- .readTimeout(30, TimeUnit.SECONDS)
- .writeTimeout(30, TimeUnit.SECONDS)
- .sslSocketFactory(sslContext.socketFactory, trustManager)
- .build()
+ return OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS)
+ .sslSocketFactory(sslContext.socketFactory, trustManager).build()
}
suspend fun registerPeerDevice(
@@ -69,41 +65,36 @@ class TellaPeerToPeerClient {
expectedFingerprint: String,
pin: String,
): RegisterPeerResult = withContext(Dispatchers.IO) {
-
val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.REGISTER)
Timber.d("Connecting to: $url")
- try {
- val payload = PeerRegisterPayload(
- pin = pin,
- nonce = UUID.randomUUID().toString()
- )
-
- val jsonPayload = Json.encodeToString(payload)
- val requestBody = jsonPayload.toRequestBody()
+ val payload = PeerRegisterPayload(
+ pin = pin, nonce = UUID.randomUUID().toString()
+ )
- val client = getClientWithFingerprintValidation(expectedFingerprint)
+ val jsonPayload = Json.encodeToString(payload)
+ val requestBody = jsonPayload.toRequestBody()
+ val client = getClientWithFingerprintValidation(expectedFingerprint)
- val request = Request.Builder()
- .url(url)
- .post(requestBody)
- .addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON)
+ val request =
+ Request.Builder().url(url).post(requestBody).addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON)
.build()
+ return@withContext try {
client.newCall(request).execute().use { response ->
val body = response.body?.string().orEmpty()
if (response.isSuccessful) {
- return@use try {
- val json = JSONObject(body)
- val sessionId = json.getString("sessionId")
- RegisterPeerResult.Success(sessionId)
- } catch (e: Exception) {
- RegisterPeerResult.Failure(Exception("Malformed JSON: ${e.message}"))
- }
+ return@use parseSessionIdFromResponse(body)
}
- // Handle known status codes
+ Timber.w(
+ """registerPeerDevice failed
+ Status: ${response.code}
+ URL: $url
+ Body: $body""".trimIndent()
+ )
+
return@use when (response.code) {
400 -> RegisterPeerResult.InvalidFormat
401 -> RegisterPeerResult.InvalidPin
@@ -114,13 +105,22 @@ class TellaPeerToPeerClient {
else -> RegisterPeerResult.Failure(Exception("Unhandled error ${response.code}: $body"))
}
}
-
} catch (e: Exception) {
- Timber.e(e, "registerPeerDevice failed")
- return@withContext RegisterPeerResult.Failure(e)
+ Timber.e(e, "registerPeerDevice request failed")
+ RegisterPeerResult.Failure(e)
}
}
+ private fun parseSessionIdFromResponse(body: String): RegisterPeerResult {
+ return try {
+ val json = JSONObject(body)
+ val sessionId = json.getString("sessionId")
+ RegisterPeerResult.Success(sessionId)
+ } catch (e: Exception) {
+ Timber.e(e, "Malformed JSON response: %s", body)
+ RegisterPeerResult.Failure(Exception("Malformed JSON: ${e.message}"))
+ }
+ }
suspend fun prepareUpload(
ip: String,
@@ -157,34 +157,39 @@ class TellaPeerToPeerClient {
.build()
client.newCall(request).execute().use { response ->
- val body = response.body.string()
-
- if (response.isSuccessful && body != null) {
- return@withContext try {
- val transmissionId =
- JSONObject(body).getString(PeerToPeerConstants.TRANSMISSION_ID_KEY)
- // Store it in the session manager
- PeerSessionManager.setTransmissionId(transmissionId)
- PrepareUploadResult.Success(transmissionId)
- } catch (e: Exception) {
- Timber.e(e, "Invalid JSON response: %s", body)
- PrepareUploadResult.Failure(Exception("Malformed server response"))
- }
- } else {
- Timber.e("Server error %d: %s", response.code, response.message)
- return@withContext when (response.code) {
- 400 -> PrepareUploadResult.BadRequest
- 403 -> PrepareUploadResult.Forbidden
- 409 -> PrepareUploadResult.Conflict
- 500 -> PrepareUploadResult.ServerError
- else -> PrepareUploadResult.Failure(Exception("Unhandled server error ${response.code}"))
- }
+ val responseBody = response.body?.string().orEmpty()
+ return@withContext if (response.isSuccessful) {
+ parseTransmissionId(responseBody)
+ } else {
+ Timber.e("Server error ${response.code}: ${response.message}")
+ handleServerError(response.code, responseBody)
}
}
} catch (e: Exception) {
Timber.e(e, "Exception during upload")
- PrepareUploadResult.Failure(e)
+ return@withContext PrepareUploadResult.Failure(e)
+ }
+ }
+
+ private fun parseTransmissionId(body: String): PrepareUploadResult {
+ return try {
+ val transmissionId = JSONObject(body).getString(PeerToPeerConstants.TRANSMISSION_ID_KEY)
+ PeerSessionManager.setTransmissionId(transmissionId)
+ PrepareUploadResult.Success(transmissionId)
+ } catch (e: Exception) {
+ Timber.e(e, "Invalid JSON response: %s", body)
+ PrepareUploadResult.Failure(Exception("Malformed server response"))
+ }
+ }
+
+ private fun handleServerError(code: Int, body: String): PrepareUploadResult {
+ return when (code) {
+ 400 -> PrepareUploadResult.BadRequest
+ 403 -> PrepareUploadResult.Forbidden
+ 409 -> PrepareUploadResult.Conflict
+ 500 -> PrepareUploadResult.ServerError
+ else -> PrepareUploadResult.Failure(Exception("Unhandled server error $code: $body"))
}
}
From 9240ee98afaeed802341a89fe846851d1bcd4539 Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 8 Jul 2025 12:55:43 +0100
Subject: [PATCH 056/153] wip save the fileId and tokens refactor code of
prepareUpload
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 12 ++--
.../data/peertopeer/TellaPeerToPeerServer.kt | 63 ++++++++++---------
.../peertopeer/remote/PrepareUploadResult.kt | 5 +-
.../peertopeer/PeerPrepareUploadResponse.kt | 7 ++-
.../fragment/peertopeer/PeerSessionManager.kt | 15 +++--
.../senderflow/PrepareUploadFragment.kt | 2 +-
6 files changed, 63 insertions(+), 41 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 3fda5b503..54c0dadc6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -17,6 +17,7 @@ import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
+import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
import org.json.JSONObject
@@ -174,15 +175,18 @@ class TellaPeerToPeerClient {
private fun parseTransmissionId(body: String): PrepareUploadResult {
return try {
- val transmissionId = JSONObject(body).getString(PeerToPeerConstants.TRANSMISSION_ID_KEY)
- PeerSessionManager.setTransmissionId(transmissionId)
- PrepareUploadResult.Success(transmissionId)
+ val response = Json.decodeFromString(body)
+
+ response.files.forEach {
+ PeerSessionManager.saveTransmissionId(it.id, it.transmissionId)
+ }
+
+ PrepareUploadResult.Success(response.files)
} catch (e: Exception) {
Timber.e(e, "Invalid JSON response: %s", body)
PrepareUploadResult.Failure(Exception("Malformed server response"))
}
}
-
private fun handleServerError(code: Int, body: String): PrepareUploadResult {
return when (code) {
400 -> PrepareUploadResult.BadRequest
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 5d1e5cdd5..fbcf7a659 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -24,6 +24,7 @@ import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
+import org.horizontal.tella.mobile.domain.peertopeer.FileInfo
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
@@ -143,36 +144,40 @@ class TellaPeerToPeerServer(
call.respond(HttpStatusCode.OK, session)
}
+ post(PeerApiRoutes.PREPARE_UPLOAD) {
+ val request = try {
+ call.receive()
+ } catch (e: Exception) {
+ call.respond(HttpStatusCode.BadRequest, "Invalid body: ${e.message}")
+ return@post
+ }
+
+ if (request.title.isBlank() || request.sessionId.isBlank() || request.files.isEmpty()) {
+ call.respond(HttpStatusCode.BadRequest, "Missing required fields")
+ return@post
+ }
+
+ if (request.sessionId != serverSession?.sessionId) {
+ call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
+ return@post
+ }
+
+ val accepted = PeerEventManager.emitPrepareUploadRequest(request)
+ if (accepted) {
+ val files = request.files.map { file ->
+ FileInfo(
+ id = file.id,
+ transmissionId = UUID.randomUUID().toString()
+ )
+ }
+ call.respond(
+ HttpStatusCode.OK,
+ PeerPrepareUploadResponse(files = files)
+ )
+ } else {
+ call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
+ }
- post(PeerApiRoutes.PREPARE_UPLOAD) {
- val request = try {
- call.receive()
- } catch (e: Exception) {
- call.respond(HttpStatusCode.BadRequest, "Invalid body: ${e.message}")
- return@post
- }
-
- if (request.title.isBlank() || request.sessionId.isBlank() || request.files.isEmpty()) {
- call.respond(HttpStatusCode.BadRequest, "Missing required fields")
- return@post
- }
-
- if (request.sessionId != serverSession?.sessionId) {
- call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
- return@post
- }
-
- val accepted = PeerEventManager.emitPrepareUploadRequest(request)
-
- if (accepted) {
- val transmissionId = UUID.randomUUID().toString()
- call.respond(
- HttpStatusCode.OK,
- PeerPrepareUploadResponse(transmissionId)
- )
- } else {
- call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
- }
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
index 3aa161221..8a39af8ec 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadResult.kt
@@ -1,10 +1,13 @@
package org.horizontal.tella.mobile.data.peertopeer.remote
+import org.horizontal.tella.mobile.domain.peertopeer.FileInfo
+
+
/**
* Created by wafa on 2/7/2025.
*/
sealed class PrepareUploadResult {
- data class Success(val transmissionId: String) : PrepareUploadResult()
+ data class Success(val transmissions: List) : PrepareUploadResult()
data object Forbidden : PrepareUploadResult()
data object BadRequest : PrepareUploadResult()
data object Conflict : PrepareUploadResult()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
index acfc25782..6ebf9d860 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
@@ -3,6 +3,11 @@ package org.horizontal.tella.mobile.domain.peertopeer
import kotlinx.serialization.Serializable
@Serializable
-data class PeerPrepareUploadResponse(
+data class FileInfo(
+ val id: String,
val transmissionId: String
+)
+
+data class PeerPrepareUploadResponse(
+ val files: List
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
index 94b6128af..cf78f1b21 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
@@ -30,12 +30,17 @@ object PeerSessionManager {
fun isSessionValid(): Boolean = connectionInfo != null
- fun setTransmissionId(id: String) {
- connectionInfo?.transmissionId = id
+ private val transmissionMap = mutableMapOf() // fileId -> transmissionId
+
+ fun saveTransmissionId(fileId: String, transmissionId: String) {
+ transmissionMap[fileId] = transmissionId
+ }
+
+ fun getTransmissionId(fileId: String): String? {
+ return transmissionMap[fileId]
}
- fun getTransmissionId(): String? = connectionInfo?.transmissionId
- fun clear() {
- connectionInfo = null
+ fun clearTransmissions() {
+ transmissionMap.clear()
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 182129333..7f85ab699 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -114,7 +114,7 @@ class PrepareUploadFragment :
}
viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
- val id = response.transmissionId
+ val transmissionId = response.files.firstOrNull()?.transmissionId
DialogUtils.showBottomMessage(
baseActivity,
getString(R.string.the_receiver_accepted_the_files_transfer),
From fa3a9bed73a084e97a09765ec41051e969563239 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 8 Jul 2025 18:03:06 +0100
Subject: [PATCH 057/153] WIP fix prepare upload files
---
.../entity/peertopeer/PeerToPeerInstance.kt | 17 +++++
.../receipentflow/RecipientSuccessFragment.kt | 4 +-
.../senderflow/PrepareUploadFragment.kt | 17 +++--
.../senderflow/UploadFilesFragment.kt | 45 +++++++++++++
.../main/res/layout/fragment_send_report.xml | 19 +++---
.../main/res/layout/fragment_upload_files.xml | 64 +++++++++++++++++++
mobile/src/main/res/values/strings.xml | 1 +
7 files changed, 147 insertions(+), 20 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
create mode 100644 mobile/src/main/res/layout/fragment_upload_files.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
new file mode 100644
index 000000000..eb3079149
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
@@ -0,0 +1,17 @@
+package org.horizontal.tella.mobile.domain.entity.peertopeer
+
+import org.horizontal.tella.mobile.domain.entity.EntityStatus
+import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
+import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
+
+class PeerToPeerInstance(
+ var id: Long = -1,
+ var updated: Long = 0,
+ var metadata: Map> = mutableMapOf(),
+ var status: EntityStatus = EntityStatus.UNKNOWN,
+ var widgetMediaFiles: List = mutableListOf(),
+ var formPartStatus: FormMediaFileStatus = FormMediaFileStatus.UNKNOWN,
+ var title: String = "",
+ var description: String = "",
+ var current: Long = 0
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 5fb8abca2..540b268f4 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -2,10 +2,7 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
-import android.widget.Toast
-import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
-import androidx.fragment.app.setFragmentResult
import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
@@ -47,6 +44,7 @@ class RecipientSuccessFragment : BaseBindingFragment
- if (bundle.get(BUNDLE_REPORT_FORM_INSTANCE) != null) {
- reportInstance = bundle.get(BUNDLE_REPORT_FORM_INSTANCE) as ReportInstance
- bundle.remove(BUNDLE_REPORT_FORM_INSTANCE)
+ if (bundle.get(BUNDLE_PEER_TO_PEER_FORM_INSTANCE) != null) {
+ peerToPeerInstance = bundle.get(BUNDLE_PEER_TO_PEER_FORM_INSTANCE) as PeerToPeerInstance
+ bundle.remove(BUNDLE_PEER_TO_PEER_FORM_INSTANCE)
}
}
- reportInstance?.let { instance ->
+ peerToPeerInstance?.let { instance ->
binding.reportTitleEt.setText(instance.title)
putFiles(viewModel.mediaFilesToVaultFiles(instance.widgetMediaFiles))
isNewDraft = false
@@ -134,7 +135,7 @@ class PrepareUploadFragment :
object : BottomSheetUtils.ActionConfirmed {
override fun accept(isConfirmed: Boolean) {
if (isConfirmed) {
- findNavController().popBackStack()
+ back()
}
}
}
@@ -165,7 +166,6 @@ class PrepareUploadFragment :
}
}
-
}
private fun exitOrSave() {
@@ -175,7 +175,6 @@ class PrepareUploadFragment :
@SuppressLint("StringFormatInvalid")
private fun initData() {
-
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
new file mode 100644
index 000000000..c0cf40d9b
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
@@ -0,0 +1,45 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.horizontal.tella.mobile.MyApplication
+import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.ReportsFormEndView
+
+class UploadFilesFragment :
+ BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return super.onCreateView(inflater, container, savedInstanceState)
+ }
+
+
+ private fun showFormEndView() {
+ /* if (reportInstance == null) {
+ return
+ }
+
+ reportInstance?.let { reportFormInstance ->
+
+ endView = ReportsFormEndView(
+ activity,
+ reportFormInstance.title,
+ reportFormInstance.description,
+ )
+ endView.setInstance(
+ reportFormInstance, MyApplication.isConnectedToInternet(baseActivity), false
+ )
+ binding.endViewContainer.removeAllViews()
+ binding.endViewContainer.addView(endView)
+ endView.clearPartsProgress(reportFormInstance)
+ }*/
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/fragment_send_report.xml b/mobile/src/main/res/layout/fragment_send_report.xml
index 8ebbf7bb1..ed3455116 100644
--- a/mobile/src/main/res/layout/fragment_send_report.xml
+++ b/mobile/src/main/res/layout/fragment_send_report.xml
@@ -32,19 +32,22 @@
app:startTitle="@string/Reports_Title_Screen" />
+ android:layout_marginEnd="@dimen/activity_horizontal_large_margin"
+ android:layout_marginStart="@dimen/activity_horizontal_large_margin"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index e63f72737..d59305d2b 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1051,4 +1051,5 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Sender\'s files rejected.
"The receiver accepted the files transfer "
Recipient rejected the files.
+ Receiving and encrypting files
From 80e89761f4bbbd250e5929bf6d253eefec596da7 Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 8 Jul 2025 19:20:15 +0100
Subject: [PATCH 058/153] WIP submission
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 26 ++++---
.../data/peertopeer/model/P2PServerState.kt | 68 +++++++++++++++++++
.../peertopeer/remote/PrepareUploadRequest.kt | 5 +-
.../fragment/peertopeer/SenderViewModel.kt | 4 +-
.../senderflow/PrepareUploadFragment.kt | 23 +------
.../res/layout/fragment_prepare_upload.xml | 2 +-
mobile/src/main/res/values-ar/strings.xml | 1 +
mobile/src/main/res/values-be/strings.xml | 1 +
mobile/src/main/res/values-blk/strings.xml | 1 +
mobile/src/main/res/values-bn/strings.xml | 1 +
mobile/src/main/res/values-es-rCU/strings.xml | 1 +
mobile/src/main/res/values-es/strings.xml | 1 +
mobile/src/main/res/values-fa-rIR/strings.xml | 1 +
mobile/src/main/res/values-fr/strings.xml | 1 +
mobile/src/main/res/values-hdpi/strings.xml | 4 ++
mobile/src/main/res/values-in/strings.xml | 1 +
mobile/src/main/res/values-kac/strings.xml | 1 +
mobile/src/main/res/values-kn/strings.xml | 1 +
mobile/src/main/res/values-ksw/strings.xml | 1 +
mobile/src/main/res/values-ku/strings.xml | 1 +
mobile/src/main/res/values-mdpi/strings.xml | 4 ++
mobile/src/main/res/values-ml/strings.xml | 1 +
mobile/src/main/res/values-my/strings.xml | 1 +
mobile/src/main/res/values-ndc/strings.xml | 1 +
mobile/src/main/res/values-pt-rMZ/strings.xml | 1 +
mobile/src/main/res/values-pt/strings.xml | 1 +
mobile/src/main/res/values-ru/strings.xml | 1 +
mobile/src/main/res/values-sn-rZW/strings.xml | 1 +
.../src/main/res/values-sw600dp/strings.xml | 4 ++
mobile/src/main/res/values-ta/strings.xml | 1 +
mobile/src/main/res/values-tr/strings.xml | 1 +
mobile/src/main/res/values-ts/strings.xml | 1 +
mobile/src/main/res/values-v21/strings.xml | 4 ++
mobile/src/main/res/values-v26/strings.xml | 4 ++
mobile/src/main/res/values-vi/strings.xml | 1 +
mobile/src/main/res/values-w820dp/strings.xml | 4 ++
mobile/src/main/res/values-xhdpi/strings.xml | 4 ++
mobile/src/main/res/values-xxhdpi/strings.xml | 4 ++
mobile/src/main/res/values/strings.xml | 1 +
39 files changed, 145 insertions(+), 40 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
create mode 100644 mobile/src/main/res/values-hdpi/strings.xml
create mode 100644 mobile/src/main/res/values-mdpi/strings.xml
create mode 100644 mobile/src/main/res/values-sw600dp/strings.xml
create mode 100644 mobile/src/main/res/values-v21/strings.xml
create mode 100644 mobile/src/main/res/values-v26/strings.xml
create mode 100644 mobile/src/main/res/values-w820dp/strings.xml
create mode 100644 mobile/src/main/res/values-xhdpi/strings.xml
create mode 100644 mobile/src/main/res/values-xxhdpi/strings.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 54c0dadc6..6e88efd39 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -11,12 +11,10 @@ import okhttp3.RequestBody.Companion.toRequestBody
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_JSON
-import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_OCTET
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
-import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
@@ -134,18 +132,18 @@ class TellaPeerToPeerClient {
val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.PREPARE_UPLOAD)
- val fileItems = files.map {
- val mimeType = it.mimeType ?: CONTENT_TYPE_OCTET
- P2PFile(
- id = it.id,
- fileName = it.name,
- size = it.size,
- fileType = mimeType,
- sha256 = it.hash
- )
- }
-
- val requestPayload = PrepareUploadRequest(title, sessionId, fileItems)
+// val fileItems = files.map {
+// val mimeType = it.mimeType ?: CONTENT_TYPE_OCTET
+// P2PFile(
+// id = it.id,
+// fileName = it.name,
+// size = it.size,
+// fileType = mimeType,
+// sha256 = it.hash
+// )
+// }
+
+ val requestPayload = PrepareUploadRequest(title, sessionId, files)
val jsonPayload = Json.encodeToString(requestPayload)
val requestBody = jsonPayload.toRequestBody()
val client = getClientWithFingerprintValidation(expectedFingerprint)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
new file mode 100644
index 000000000..c170114b6
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
@@ -0,0 +1,68 @@
+package org.horizontal.tella.mobile.data.peertopeer.model
+
+// --- ENUMS ---
+
+enum class P2PFileStatus {
+ QUEUE,
+ SENDING,
+ FAILED,
+ FINISHED
+}
+
+enum class SessionStatus {
+ WAITING,
+ SENDING,
+ FINISHED,
+ FINISHED_WITH_ERRORS
+}
+
+data class P2PFile(
+ val name: String,
+ val size: Long
+)
+
+data class ReceivingFile(
+ var file: P2PFile,
+ var status: P2PFileStatus = P2PFileStatus.QUEUE,
+ var transmissionId: String? = null,
+ var path: String? = null,
+ var bytesReceived: Int = 0
+)
+
+class P2PSession(
+ val sessionId: String,
+ var status: SessionStatus = SessionStatus.WAITING,
+ var files: MutableMap = mutableMapOf(),
+ var title: String? = null
+) {
+ val isActive: Boolean
+ get() = status == SessionStatus.WAITING || status == SessionStatus.SENDING
+
+ val hasFiles: Boolean
+ get() = files.isNotEmpty()
+}
+
+class P2PServerState(
+ var pin: String? = null,
+ var session: P2PSession? = null,
+ private var failedAttempts: Int = 0,
+ private var isUsingManualConnection: Boolean = false
+) {
+ private val maxFailedAttempts = 3
+
+ val hasReachedMaxAttempts: Boolean
+ get() = failedAttempts >= maxFailedAttempts
+
+ fun incrementFailedAttempts() {
+ failedAttempts++
+ }
+
+ fun reset() {
+ pin = null
+ session = null
+ failedAttempts = 0
+ isUsingManualConnection = false
+ }
+
+ fun getFailedAttempts(): Int = failedAttempts
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
index 803f30c08..d83eb6d7f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
@@ -1,12 +1,13 @@
package org.horizontal.tella.mobile.data.peertopeer.remote
+import com.hzontal.tella_vault.VaultFile
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
+import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
@Serializable
data class PrepareUploadRequest(
val title: String,
@SerialName("sessionId") val sessionId: String,
- val files: List
+ val files: List
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index e78e013ae..c897f9d72 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -82,8 +82,8 @@ class SenderViewModel @Inject constructor(
sessionId = info.sessionId
)) {
is PrepareUploadResult.Success -> {
- Timber.d("Success: transmissionId = ${result.transmissionId}")
- _prepareResults.postValue(PeerPrepareUploadResponse(result.transmissionId))
+ Timber.d("Success: transmissionId = ${result.transmissions}")
+ _prepareResults.postValue(PeerPrepareUploadResponse(result.transmissions))
}
is PrepareUploadResult.Forbidden -> {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 2175104ab..8bfdfb42f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -54,7 +54,6 @@ class PrepareUploadFragment :
private var isTitleEnabled = false
private var peerToPeerInstance: PeerToPeerInstance? = null
private val viewModel: SenderViewModel by viewModels()
- private var isNewDraft = true
private var disposables =
MyApplication.bus().createCompositeDisposable()
@@ -73,7 +72,6 @@ class PrepareUploadFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
initView()
- initData()
onAudioRecordingListener()
}
@@ -100,7 +98,6 @@ class PrepareUploadFragment :
peerToPeerInstance?.let { instance ->
binding.reportTitleEt.setText(instance.title)
putFiles(viewModel.mediaFilesToVaultFiles(instance.widgetMediaFiles))
- isNewDraft = false
}
val navBackStackEntry = findNavController().currentBackStackEntry
navBackStackEntry?.savedStateHandle
@@ -115,7 +112,7 @@ class PrepareUploadFragment :
}
viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
- val transmissionId = response.files.firstOrNull()?.transmissionId
+ // val transmissionId = response.files.firstOrNull()?.transmissionId
DialogUtils.showBottomMessage(
baseActivity,
getString(R.string.the_receiver_accepted_the_files_transfer),
@@ -142,18 +139,8 @@ class PrepareUploadFragment :
)
}
highLightButtonsInit()
- checkIsNewDraftEntry()
}
- private fun checkIsNewDraftEntry() {
- if (isNewDraft) {
- binding.sendReportBtn.text = getString(R.string.collect_end_action_submit)
- } else {
- binding.sendReportBtn.text = getString(R.string.Send_Action_Label)
- }
- }
-
-
private fun highLightButtonsInit() {
binding.apply {
reportTitleEt.let { title ->
@@ -169,15 +156,9 @@ class PrepareUploadFragment :
}
private fun exitOrSave() {
-
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
- @SuppressLint("StringFormatInvalid")
- private fun initData() {
-
- }
-
-
private fun showSelectFilesSheet() {
showVaultSelectFilesSheet(baseActivity.supportFragmentManager,
baseActivity.getString(R.string.Uwazi_WidgetMedia_Take_Photo),
diff --git a/mobile/src/main/res/layout/fragment_prepare_upload.xml b/mobile/src/main/res/layout/fragment_prepare_upload.xml
index a6d6ba9b3..9a97778df 100644
--- a/mobile/src/main/res/layout/fragment_prepare_upload.xml
+++ b/mobile/src/main/res/layout/fragment_prepare_upload.xml
@@ -108,7 +108,7 @@
android:background="@drawable/bg_round_orange16_btn"
android:fontFamily="@font/open_sans"
android:gravity="center"
- android:text="@string/collect.end_action_submit"
+ android:text="@string/send_files_title"
android:textAlignment="center"
android:textColor="@color/btn_dark_letter"
android:textSize="16sp"
diff --git a/mobile/src/main/res/values-ar/strings.xml b/mobile/src/main/res/values-ar/strings.xml
index 88329fa03..47293ef16 100644
--- a/mobile/src/main/res/values-ar/strings.xml
+++ b/mobile/src/main/res/values-ar/strings.xml
@@ -1002,4 +1002,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-be/strings.xml b/mobile/src/main/res/values-be/strings.xml
index e15cf9128..cd0b91ffc 100644
--- a/mobile/src/main/res/values-be/strings.xml
+++ b/mobile/src/main/res/values-be/strings.xml
@@ -1003,4 +1003,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-blk/strings.xml b/mobile/src/main/res/values-blk/strings.xml
index 1b45e091b..2a313d4cb 100644
--- a/mobile/src/main/res/values-blk/strings.xml
+++ b/mobile/src/main/res/values-blk/strings.xml
@@ -141,4 +141,5 @@
Feedback
Your feedback has been sent
share feedback
+ Send files
diff --git a/mobile/src/main/res/values-bn/strings.xml b/mobile/src/main/res/values-bn/strings.xml
index 84a567b2f..0dbe34939 100644
--- a/mobile/src/main/res/values-bn/strings.xml
+++ b/mobile/src/main/res/values-bn/strings.xml
@@ -983,4 +983,5 @@
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-es-rCU/strings.xml b/mobile/src/main/res/values-es-rCU/strings.xml
index 2eee28df0..4a0dae9f7 100644
--- a/mobile/src/main/res/values-es-rCU/strings.xml
+++ b/mobile/src/main/res/values-es-rCU/strings.xml
@@ -1004,4 +1004,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-es/strings.xml b/mobile/src/main/res/values-es/strings.xml
index 975dca38f..3386c00f5 100644
--- a/mobile/src/main/res/values-es/strings.xml
+++ b/mobile/src/main/res/values-es/strings.xml
@@ -987,4 +987,5 @@ Este feedback es anónimo, así que asegúrate de incluir tu información de con
El reporte se envió correctamente.
Adjuntar archivo
%1$s eviado correctamente
+ Send files
diff --git a/mobile/src/main/res/values-fa-rIR/strings.xml b/mobile/src/main/res/values-fa-rIR/strings.xml
index acd0716ca..a35c05c72 100644
--- a/mobile/src/main/res/values-fa-rIR/strings.xml
+++ b/mobile/src/main/res/values-fa-rIR/strings.xml
@@ -1000,4 +1000,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-fr/strings.xml b/mobile/src/main/res/values-fr/strings.xml
index 3663722c6..92a94193d 100644
--- a/mobile/src/main/res/values-fr/strings.xml
+++ b/mobile/src/main/res/values-fr/strings.xml
@@ -997,4 +997,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-hdpi/strings.xml b/mobile/src/main/res/values-hdpi/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-hdpi/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-in/strings.xml b/mobile/src/main/res/values-in/strings.xml
index f4fc275ce..5eb7d714a 100644
--- a/mobile/src/main/res/values-in/strings.xml
+++ b/mobile/src/main/res/values-in/strings.xml
@@ -985,4 +985,5 @@ Apakah Anda ingin membagikan analitik kepada tim Tella?
Your report has successfully been submitted.
Lampirkan berkas
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-kac/strings.xml b/mobile/src/main/res/values-kac/strings.xml
index 41bdb3bb3..ca83e630b 100644
--- a/mobile/src/main/res/values-kac/strings.xml
+++ b/mobile/src/main/res/values-kac/strings.xml
@@ -1003,4 +1003,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-kn/strings.xml b/mobile/src/main/res/values-kn/strings.xml
index 0cbd35125..68cb63707 100644
--- a/mobile/src/main/res/values-kn/strings.xml
+++ b/mobile/src/main/res/values-kn/strings.xml
@@ -1003,4 +1003,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-ksw/strings.xml b/mobile/src/main/res/values-ksw/strings.xml
index 4925acdbc..e2d812a15 100644
--- a/mobile/src/main/res/values-ksw/strings.xml
+++ b/mobile/src/main/res/values-ksw/strings.xml
@@ -986,4 +986,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-ku/strings.xml b/mobile/src/main/res/values-ku/strings.xml
index b24e629d1..88200b941 100644
--- a/mobile/src/main/res/values-ku/strings.xml
+++ b/mobile/src/main/res/values-ku/strings.xml
@@ -998,4 +998,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-mdpi/strings.xml b/mobile/src/main/res/values-mdpi/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-mdpi/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ml/strings.xml b/mobile/src/main/res/values-ml/strings.xml
index cf87b4b5a..8be73fa59 100644
--- a/mobile/src/main/res/values-ml/strings.xml
+++ b/mobile/src/main/res/values-ml/strings.xml
@@ -1003,4 +1003,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-my/strings.xml b/mobile/src/main/res/values-my/strings.xml
index b4e857b54..0a23a7884 100644
--- a/mobile/src/main/res/values-my/strings.xml
+++ b/mobile/src/main/res/values-my/strings.xml
@@ -986,4 +986,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-ndc/strings.xml b/mobile/src/main/res/values-ndc/strings.xml
index e51eeea79..e10faa1c3 100644
--- a/mobile/src/main/res/values-ndc/strings.xml
+++ b/mobile/src/main/res/values-ndc/strings.xml
@@ -977,4 +977,5 @@ Wainda kupaurirana maonere no chikwatha Tella?
Tsamba yako yatumirwa swakanaka
Kuisa gwaro mapwepo
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-pt-rMZ/strings.xml b/mobile/src/main/res/values-pt-rMZ/strings.xml
index 7ef64346b..a18e9217f 100644
--- a/mobile/src/main/res/values-pt-rMZ/strings.xml
+++ b/mobile/src/main/res/values-pt-rMZ/strings.xml
@@ -989,4 +989,5 @@ Gostaria de partilhar dados com a equipa do Tella?
Your report has successfully been submitted.
Anexar arquivo
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-pt/strings.xml b/mobile/src/main/res/values-pt/strings.xml
index f7fae1d91..c0bd0c369 100644
--- a/mobile/src/main/res/values-pt/strings.xml
+++ b/mobile/src/main/res/values-pt/strings.xml
@@ -1003,4 +1003,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-ru/strings.xml b/mobile/src/main/res/values-ru/strings.xml
index 91085941b..31a6be0bc 100644
--- a/mobile/src/main/res/values-ru/strings.xml
+++ b/mobile/src/main/res/values-ru/strings.xml
@@ -1013,4 +1013,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-sn-rZW/strings.xml b/mobile/src/main/res/values-sn-rZW/strings.xml
index e51eeea79..e10faa1c3 100644
--- a/mobile/src/main/res/values-sn-rZW/strings.xml
+++ b/mobile/src/main/res/values-sn-rZW/strings.xml
@@ -977,4 +977,5 @@ Wainda kupaurirana maonere no chikwatha Tella?
Tsamba yako yatumirwa swakanaka
Kuisa gwaro mapwepo
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-sw600dp/strings.xml b/mobile/src/main/res/values-sw600dp/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-sw600dp/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ta/strings.xml b/mobile/src/main/res/values-ta/strings.xml
index dc0fb6e84..9c5087049 100644
--- a/mobile/src/main/res/values-ta/strings.xml
+++ b/mobile/src/main/res/values-ta/strings.xml
@@ -1003,4 +1003,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-tr/strings.xml b/mobile/src/main/res/values-tr/strings.xml
index 5cec2fede..9dd131245 100644
--- a/mobile/src/main/res/values-tr/strings.xml
+++ b/mobile/src/main/res/values-tr/strings.xml
@@ -983,4 +983,5 @@ Tella ekibiyle analizleri paylaşmak ister misiniz?
Your report has successfully been submitted.
Dosya ekle
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-ts/strings.xml b/mobile/src/main/res/values-ts/strings.xml
index c3d5ed713..3f77cd650 100644
--- a/mobile/src/main/res/values-ts/strings.xml
+++ b/mobile/src/main/res/values-ts/strings.xml
@@ -973,4 +973,5 @@ yi fanele ku ku nyika vutshokotshoko bya servhidor.
Your report has successfully been submitted.
Nghenisa arkivho
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-v21/strings.xml b/mobile/src/main/res/values-v21/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-v21/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-v26/strings.xml b/mobile/src/main/res/values-v26/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-v26/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-vi/strings.xml b/mobile/src/main/res/values-vi/strings.xml
index 8821ff75b..1285723ee 100644
--- a/mobile/src/main/res/values-vi/strings.xml
+++ b/mobile/src/main/res/values-vi/strings.xml
@@ -993,4 +993,5 @@ Would you like to share analytics with the Tella team?
Your report has successfully been submitted.
Attach file
%1$s successfully submitted
+ Send files
diff --git a/mobile/src/main/res/values-w820dp/strings.xml b/mobile/src/main/res/values-w820dp/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-w820dp/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xhdpi/strings.xml b/mobile/src/main/res/values-xhdpi/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-xhdpi/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xxhdpi/strings.xml b/mobile/src/main/res/values-xxhdpi/strings.xml
new file mode 100644
index 000000000..67ac84b3d
--- /dev/null
+++ b/mobile/src/main/res/values-xxhdpi/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Send files
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index d59305d2b..bd0a26dd8 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1052,4 +1052,5 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
"The receiver accepted the files transfer "
Recipient rejected the files.
Receiving and encrypting files
+ Send files
From 3ada26c2b5b2836cbf82d1bec78e546354f6b802 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 9 Jul 2025 12:38:17 +0100
Subject: [PATCH 059/153] WIP fix state
---
...PeerServer.kt => TELLAPeerToPeerServer.kt} | 90 ++++++++++++-------
.../managers/PeerServerStarterManager.kt | 15 ++--
.../data/peertopeer/model/P2PServerState.kt | 10 +--
.../peertopeer/remote/PrepareUploadRequest.kt | 5 +-
.../mobile/domain/peertopeer/FileItem.kt | 12 ---
.../tella/mobile/domain/peertopeer/P2PFile.kt | 42 +++++++++
.../base/BaseReportsSendFragment.kt | 2 +-
7 files changed, 115 insertions(+), 61 deletions(-)
rename mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/{TellaPeerToPeerServer.kt => TELLAPeerToPeerServer.kt} (67%)
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/FileItem.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
similarity index 67%
rename from mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
index fbcf7a659..01a0bff05 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
@@ -1,6 +1,5 @@
package org.horizontal.tella.mobile.data.peertopeer
-import android.util.Log
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.call
@@ -22,15 +21,18 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
+import org.horizontal.tella.mobile.data.peertopeer.model.ReceivingFile
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.domain.peertopeer.FileInfo
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
+import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.domain.peertopeer.PeerResponse
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
-import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
@@ -38,14 +40,15 @@ import java.util.UUID
const val port = 53317
-class TellaPeerToPeerServer(
+class TELLAPeerToPeerServer(
private val ip: String,
private val serverPort: Int = port,
- private val pin: Int,
+ private val pin: String,
private val keyPair: KeyPair,
private val certificate: X509Certificate,
private val keyStoreConfig: KeyStoreConfig,
private val peerToPeerManager: PeerToPeerManager,
+ private val p2PServerState: P2PServerState
) : TellaServer {
private var serverSession: PeerResponse? = null
private var engine: ApplicationEngine? = null
@@ -82,7 +85,6 @@ class TellaPeerToPeerServer(
routing {
// Root route to confirm the server is running
get("/") {
- Log.i("Test", "Server started")
call.respondText("The server is running securely over HTTPS.")
}
@@ -103,7 +105,7 @@ class TellaPeerToPeerServer(
}
//TODO CHECK IF THE PIN IS CORRECT
- if (!isValidPin(request.pin) || pin.toString() != request.pin) {
+ if (!isValidPin(request.pin) || pin != request.pin) {
call.respond(HttpStatusCode.Unauthorized, "Invalid PIN")
return@post
}
@@ -138,47 +140,69 @@ class TellaPeerToPeerServer(
}
launch {
+ p2PServerState.apply {
+ pin = this@TELLAPeerToPeerServer.pin
+
+ }
PeerEventManager.emitRegistrationSuccess()
}
call.respond(HttpStatusCode.OK, session)
}
+ post(PeerApiRoutes.PREPARE_UPLOAD) {
+ val request = try {
+ call.receive()
+ } catch (e: Exception) {
+ call.respond(HttpStatusCode.BadRequest, "Invalid body: ${e.message}")
+ return@post
+ }
- post(PeerApiRoutes.PREPARE_UPLOAD) {
- val request = try {
- call.receive()
- } catch (e: Exception) {
- call.respond(HttpStatusCode.BadRequest, "Invalid body: ${e.message}")
- return@post
- }
+ if (request.title.isBlank() || request.sessionId.isBlank() || request.files.isEmpty()) {
+ call.respond(HttpStatusCode.BadRequest, "Missing required fields")
+ return@post
+ }
- if (request.title.isBlank() || request.sessionId.isBlank() || request.files.isEmpty()) {
- call.respond(HttpStatusCode.BadRequest, "Missing required fields")
- return@post
- }
+ if (request.sessionId != serverSession?.sessionId) {
+ call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
+ return@post
+ }
- if (request.sessionId != serverSession?.sessionId) {
- call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
+ val accepted = PeerEventManager.emitPrepareUploadRequest(request)
+ if (accepted) {
+ val sessionId = serverSession?.sessionId ?: run {
+ call.respond(HttpStatusCode.InternalServerError, "Missing session")
return@post
}
- val accepted = PeerEventManager.emitPrepareUploadRequest(request)
- if (accepted) {
- val files = request.files.map { file ->
- FileInfo(
- id = file.id,
- transmissionId = UUID.randomUUID().toString()
- )
- }
- call.respond(
- HttpStatusCode.OK,
- PeerPrepareUploadResponse(files = files)
+ // Create a new P2PSession
+ val session = P2PSession(sessionId = sessionId, title = request.title)
+
+ val responseFiles = request.files.map { file ->
+ val transmissionId = UUID.randomUUID().toString()
+ val receivingFile = ReceivingFile(
+ file = file,
+ transmissionId = transmissionId
+ )
+ session.files[transmissionId] = receivingFile
+
+ FileInfo(
+ id = file.id,
+ transmissionId = transmissionId
)
- } else {
- call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
}
+ // Save session to server state
+ p2PServerState.session = session
+
+ call.respond(
+ HttpStatusCode.OK,
+ PeerPrepareUploadResponse(files = responseFiles)
+ )
+ } else {
+ call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
+ }
}
+
}
}
@@ -190,6 +214,6 @@ class TellaPeerToPeerServer(
}
private fun isValidPin(pin: String): Boolean {
- return pin.length == 6 // or whatever your rule is
+ return pin.length == 6
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
index d396f078a..6628474eb 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
@@ -3,7 +3,8 @@ package org.horizontal.tella.mobile.data.peertopeer.managers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerServer
+import org.horizontal.tella.mobile.data.peertopeer.TELLAPeerToPeerServer
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import java.security.KeyPair
import java.security.cert.X509Certificate
@@ -14,23 +15,25 @@ import javax.inject.Singleton
class PeerServerStarterManager @Inject constructor(
private val peerToPeerManager: PeerToPeerManager
) {
- private var server: TellaPeerToPeerServer? = null
+ private var server: TELLAPeerToPeerServer? = null
fun startServer(
ip: String,
keyPair: KeyPair,
- pin: Int,
+ pin: String,
cert: X509Certificate,
- config: KeyStoreConfig
+ config: KeyStoreConfig,
+ p2PServerState: P2PServerState,
) {
if (server == null) {
- server = TellaPeerToPeerServer(
+ server = TELLAPeerToPeerServer(
ip = ip,
keyPair = keyPair,
pin = pin,
certificate = cert,
keyStoreConfig = config,
- peerToPeerManager = peerToPeerManager
+ peerToPeerManager = peerToPeerManager,
+ p2PServerState = p2PServerState
)
server?.start()
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
index c170114b6..2d5c0ca4a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
@@ -1,5 +1,7 @@
package org.horizontal.tella.mobile.data.peertopeer.model
+import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
+
// --- ENUMS ---
enum class P2PFileStatus {
@@ -16,11 +18,6 @@ enum class SessionStatus {
FINISHED_WITH_ERRORS
}
-data class P2PFile(
- val name: String,
- val size: Long
-)
-
data class ReceivingFile(
var file: P2PFile,
var status: P2PFileStatus = P2PFileStatus.QUEUE,
@@ -30,7 +27,7 @@ data class ReceivingFile(
)
class P2PSession(
- val sessionId: String,
+ var sessionId: String,
var status: SessionStatus = SessionStatus.WAITING,
var files: MutableMap = mutableMapOf(),
var title: String? = null
@@ -46,6 +43,7 @@ class P2PServerState(
var pin: String? = null,
var session: P2PSession? = null,
private var failedAttempts: Int = 0,
+ //TODO ASK DHEKRA ABOIUT THIS
private var isUsingManualConnection: Boolean = false
) {
private val maxFailedAttempts = 3
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
index d83eb6d7f..803f30c08 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PrepareUploadRequest.kt
@@ -1,13 +1,12 @@
package org.horizontal.tella.mobile.data.peertopeer.remote
-import com.hzontal.tella_vault.VaultFile
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
+import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
@Serializable
data class PrepareUploadRequest(
val title: String,
@SerialName("sessionId") val sessionId: String,
- val files: List
+ val files: List
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/FileItem.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/FileItem.kt
deleted file mode 100644
index f089be108..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/FileItem.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.horizontal.tella.mobile.domain.peertopeer
-
-import kotlinx.serialization.Serializable
-
-@Serializable
-data class P2PFile(
- val id: String,
- val fileName: String,
- val size: Long,
- val fileType: String,
- val sha256: String
-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt
new file mode 100644
index 000000000..c4a6db2d8
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt
@@ -0,0 +1,42 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class P2PFile(
+ val id: String,
+ val fileName: String,
+ val size: Long,
+ val fileType: String,
+ val sha256: String,
+ val thumb: ByteArray? = null
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as P2PFile
+
+ if (id != other.id) return false
+ if (fileName != other.fileName) return false
+ if (size != other.size) return false
+ if (fileType != other.fileType) return false
+ if (sha256 != other.sha256) return false
+ if (thumb != null) {
+ if (other.thumb == null) return false
+ if (!thumb.contentEquals(other.thumb)) return false
+ } else if (other.thumb != null) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = id.hashCode()
+ result = 31 * result + fileName.hashCode()
+ result = 31 * result + size.hashCode()
+ result = 31 * result + fileType.hashCode()
+ result = 31 * result + sha256.hashCode()
+ result = 31 * result + (thumb?.contentHashCode() ?: 0)
+ return result
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt
index 1607e6f4c..635bb683b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt
@@ -82,7 +82,7 @@ abstract class BaseReportsSendFragment :
binding.toolbar.backClickListener = {
handleBackButton()
}
- binding.toolbar.setRightIcon(icon = -1)
+ binding.setRightIcon(icon = -1)
if (reportInstance?.status == EntityStatus.SUBMITTED) {
binding.nextBtn.hide()
From af896c6fee1573e7b68cad7e22b87ac611be5ca0 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 9 Jul 2025 12:38:52 +0100
Subject: [PATCH 060/153] clean code
---
.../tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
index 01a0bff05..c70929fd1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
@@ -174,9 +174,9 @@ class TELLAPeerToPeerServer(
return@post
}
- // Create a new P2PSession
val session = P2PSession(sessionId = sessionId, title = request.title)
+
val responseFiles = request.files.map { file ->
val transmissionId = UUID.randomUUID().toString()
val receivingFile = ReceivingFile(
@@ -191,7 +191,6 @@ class TELLAPeerToPeerServer(
)
}
- // Save session to server state
p2PServerState.session = session
call.respond(
From 7968532e1989977b795ea05ecd650955213d90ce Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 9 Jul 2025 20:17:14 +0100
Subject: [PATCH 061/153] wip submission files workflow
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 26 +-
...PeerServer.kt => TellaPeerToPeerServer.kt} | 4 +-
.../managers/PeerServerStarterManager.kt | 6 +-
.../domain/entity/collect/FormMediaFile.java | 3 +
.../entity/peertopeer/PeerToPeerInstance.kt | 5 +-
.../tella/mobile/util/NavigationManager.kt | 13 +-
.../mobile/views/base_ui/BaseActivity.kt | 5 +-
.../base/BaseReportsSendFragment.kt | 2 +-
.../fragment/peertopeer/PeerSessionManager.kt | 19 +-
.../fragment/peertopeer/SenderViewModel.kt | 29 ++-
.../fragment/peertopeer/di/PeerModule.kt | 7 +
.../receipentflow/ConnectHotspotFragment.kt | 10 +-
.../receipentflow/QRCodeFragment.kt | 13 +-
.../senderflow/PrepareUploadFragment.kt | 67 ++---
.../senderflow/UploadFilesFragment.kt | 54 ++--
.../senderflow/WaitingSenderFragment.kt | 15 +-
.../uwazi/widgets/PeerToPeerEndView.java | 246 ++++++++++++++++++
.../main/res/layout/fragment_send_report.xml | 19 +-
.../main/res/layout/fragment_upload_files.xml | 30 ++-
.../res/navigation/peer_to_peer_graph.xml | 12 +-
mobile/src/main/res/values/strings.xml | 1 +
21 files changed, 437 insertions(+), 149 deletions(-)
rename mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/{TELLAPeerToPeerServer.kt => TellaPeerToPeerServer.kt} (98%)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 6e88efd39..54c0dadc6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -11,10 +11,12 @@ import okhttp3.RequestBody.Companion.toRequestBody
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_JSON
+import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_OCTET
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
+import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
@@ -132,18 +134,18 @@ class TellaPeerToPeerClient {
val url = PeerApiRoutes.buildUrl(ip, port, PeerApiRoutes.PREPARE_UPLOAD)
-// val fileItems = files.map {
-// val mimeType = it.mimeType ?: CONTENT_TYPE_OCTET
-// P2PFile(
-// id = it.id,
-// fileName = it.name,
-// size = it.size,
-// fileType = mimeType,
-// sha256 = it.hash
-// )
-// }
-
- val requestPayload = PrepareUploadRequest(title, sessionId, files)
+ val fileItems = files.map {
+ val mimeType = it.mimeType ?: CONTENT_TYPE_OCTET
+ P2PFile(
+ id = it.id,
+ fileName = it.name,
+ size = it.size,
+ fileType = mimeType,
+ sha256 = it.hash
+ )
+ }
+
+ val requestPayload = PrepareUploadRequest(title, sessionId, fileItems)
val jsonPayload = Json.encodeToString(requestPayload)
val requestBody = jsonPayload.toRequestBody()
val client = getClientWithFingerprintValidation(expectedFingerprint)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
similarity index 98%
rename from mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index c70929fd1..9642664c5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TELLAPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -40,7 +40,7 @@ import java.util.UUID
const val port = 53317
-class TELLAPeerToPeerServer(
+class TellaPeerToPeerServer(
private val ip: String,
private val serverPort: Int = port,
private val pin: String,
@@ -141,7 +141,7 @@ class TELLAPeerToPeerServer(
launch {
p2PServerState.apply {
- pin = this@TELLAPeerToPeerServer.pin
+ pin = this@TellaPeerToPeerServer.pin
}
PeerEventManager.emitRegistrationSuccess()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
index 6628474eb..6449bc74f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
@@ -3,7 +3,7 @@ package org.horizontal.tella.mobile.data.peertopeer.managers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import org.horizontal.tella.mobile.data.peertopeer.TELLAPeerToPeerServer
+import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerServer
import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import java.security.KeyPair
@@ -15,7 +15,7 @@ import javax.inject.Singleton
class PeerServerStarterManager @Inject constructor(
private val peerToPeerManager: PeerToPeerManager
) {
- private var server: TELLAPeerToPeerServer? = null
+ private var server: TellaPeerToPeerServer? = null
fun startServer(
ip: String,
@@ -26,7 +26,7 @@ class PeerServerStarterManager @Inject constructor(
p2PServerState: P2PServerState,
) {
if (server == null) {
- server = TELLAPeerToPeerServer(
+ server = TellaPeerToPeerServer(
ip = ip,
keyPair = keyPair,
pin = pin,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/collect/FormMediaFile.java b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/collect/FormMediaFile.java
index 2db77b42f..1c51dc4ac 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/collect/FormMediaFile.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/collect/FormMediaFile.java
@@ -9,12 +9,15 @@ public class FormMediaFile extends VaultFile {
public FormMediaFileStatus status; // break away from getters/setters :)
public boolean uploading;
public long uploadedSize;
+ public String transmissionId;
+
public FormMediaFile() {
super();
status = FormMediaFileStatus.UNKNOWN;
uploading = true;
uploadedSize = 0;
+ transmissionId = "";
}
public static FormMediaFile fromMediaFile(@NonNull VaultFile vaultFile) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
index eb3079149..2312e005a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
@@ -7,11 +7,10 @@ import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
class PeerToPeerInstance(
var id: Long = -1,
var updated: Long = 0,
- var metadata: Map> = mutableMapOf(),
var status: EntityStatus = EntityStatus.UNKNOWN,
var widgetMediaFiles: List = mutableListOf(),
var formPartStatus: FormMediaFileStatus = FormMediaFileStatus.UNKNOWN,
var title: String = "",
- var description: String = "",
- var current: Long = 0
+ var current: Long = 0,
+ var sessionID: String = ""
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index bbc243016..dc5d9cd3f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -185,6 +185,7 @@ class NavigationManager(
fun navigateFromScanQrCodeToDeviceInfo() {
navigateToWithBundle(R.id.action_qrCodeScreen_to_deviceInfoScreen)
}
+
fun navigateFromScanQrCodeToPrepareUploadFragment() {
navigateToWithBundle(R.id.action_scanQrCodeScreen_to_prepareUploadFragment)
}
@@ -197,7 +198,7 @@ class NavigationManager(
navigateToWithBundle(R.id.action_senderManualConnectionScreen_to_connectManuallyVerificationScreen)
}
- fun navigateFromDeviceInfoScreenTRecipientVerificationScreen(){
+ fun navigateFromDeviceInfoScreenTRecipientVerificationScreen() {
navigateToWithBundle(R.id.action_deviceInfoScreen_to_recipientVerificationScreen)
}
@@ -209,18 +210,22 @@ class NavigationManager(
navigateToWithBundle(R.id.action_prepareUploadFragment_to_waitingSenderFragment)
}
- fun navigateConnectManuallyVerificationFragmentToprepareUploadFragment(){
+ fun navigateConnectManuallyVerificationFragmentToprepareUploadFragment() {
navigateToWithBundle(R.id.action_connectManuallyVerificationFragment_to_prepareUploadFragment)
}
- fun navigateFromRecipientVerificationScreenToWaitingReceiverFragment(){
+ fun navigateFromRecipientVerificationScreenToWaitingReceiverFragment() {
navigateToWithBundle(R.id.action_recipientVerificationScreen_to_waitingReceiverFragment)
}
- fun navigateFromWaitingReceiverFragmentToRecipientSuccessFragment(){
+ fun navigateFromWaitingReceiverFragmentToRecipientSuccessFragment() {
navigateToWithBundle(R.id.action_waitingReceiverFragment_to_recipientSuccessFragment)
}
+ fun navigateFromWaitingSenderFragmentToUploadFilesFragment() {
+ navigateToWithBundle(R.id.action_waitingSenderFragment_to_uploadFilesFragment)
+ }
+
fun navigateBackToStartNearBySharingFragmentAndClearBackStack() {
navControllerProvider.navController.navigate(
R.id.startNearBySharingFragment,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseActivity.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseActivity.kt
index c005a9afd..256c82474 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseActivity.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/base_ui/BaseActivity.kt
@@ -32,7 +32,8 @@ abstract class BaseActivity : AppCompatActivity() {
var isManualOrientation = false
private lateinit var container: ViewGroup
private lateinit var loading: View
- @Inject lateinit var divviupUtils : DivviupUtils
+ @Inject
+ lateinit var divviupUtils: DivviupUtils
override fun onCreate(savedInstanceState: Bundle?) {
// Let content draw behind system bars
WindowCompat.setDecorFitsSystemWindows(window, false)
@@ -146,7 +147,7 @@ abstract class BaseActivity : AppCompatActivity() {
.commitAllowingStateLoss()
}
- fun addFragment(container : Int, fragment: Fragment, tag : String ){
+ fun addFragment(container: Int, fragment: Fragment, tag: String) {
val existingFragment = supportFragmentManager.findFragmentByTag(tag)
if (existingFragment == null) {
supportFragmentManager.beginTransaction()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt
index 635bb683b..1607e6f4c 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/main_connexions/base/BaseReportsSendFragment.kt
@@ -82,7 +82,7 @@ abstract class BaseReportsSendFragment :
binding.toolbar.backClickListener = {
handleBackButton()
}
- binding.setRightIcon(icon = -1)
+ binding.toolbar.setRightIcon(icon = -1)
if (reportInstance?.status == EntityStatus.SUBMITTED) {
binding.nextBtn.hide()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
index cf78f1b21..9e6b6b346 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
@@ -1,9 +1,6 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer
-/**
- * Created by wafa on 2/6/2025.
- */
-
+//TODO CHECK IF WE SHOULD REMOVE THIS
data class PeerConnectionInfo(
val ip: String = "",
val port: String = "",
@@ -11,7 +8,6 @@ data class PeerConnectionInfo(
val sessionId: String = "",
val hash: String = "",
val pin: Int = 0,
- var transmissionId: String? = null
)
object PeerSessionManager {
@@ -30,17 +26,4 @@ object PeerSessionManager {
fun isSessionValid(): Boolean = connectionInfo != null
- private val transmissionMap = mutableMapOf() // fileId -> transmissionId
-
- fun saveTransmissionId(fileId: String, transmissionId: String) {
- transmissionMap[fileId] = transmissionId
- }
-
- fun getTransmissionId(fileId: String): String? {
- return transmissionMap[fileId]
- }
-
- fun clearTransmissions() {
- transmissionMap.clear()
- }
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index c897f9d72..a7a4db0bb 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -16,6 +16,8 @@ import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
+import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
+import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.util.Event
import org.horizontal.tella.mobile.util.fromJsonToObjectList
@@ -31,7 +33,7 @@ class SenderViewModel @Inject constructor(
val prepareResults: LiveData = _prepareResults
private val _prepareRejected = MutableLiveData>()
val prepareRejected: LiveData> = _prepareRejected
-
+ var peerToPeerInstance: PeerToPeerInstance? = null
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
@@ -63,6 +65,16 @@ class SenderViewModel @Inject constructor(
return vaultFiles
}
+ fun vaultFilesToMediaFiles(files: List): List {
+ val vaultFiles = mutableListOf()
+ files.map { vaultFile ->
+ val mediaFile = FormMediaFile.fromMediaFile(vaultFile)
+ mediaFile.status = FormMediaFileStatus.NOT_SUBMITTED
+ vaultFiles.add(FormMediaFile.fromMediaFile(vaultFile))
+ }
+ return vaultFiles
+ }
+
fun prepareUploadsFromVaultFiles(
files: List,
title: String = "Title of the report"
@@ -82,8 +94,19 @@ class SenderViewModel @Inject constructor(
sessionId = info.sessionId
)) {
is PrepareUploadResult.Success -> {
- Timber.d("Success: transmissionId = ${result.transmissions}")
+ peerToPeerInstance?.sessionID = info.sessionId
+ val fileInfoMap = result.transmissions.associateBy { it.id }
+
+ peerToPeerInstance?.widgetMediaFiles?.forEach { mediaFile ->
+ fileInfoMap[mediaFile.id]?.let { fileInfo ->
+ mediaFile.transmissionId = fileInfo.transmissionId
+ }
+ }
+
_prepareResults.postValue(PeerPrepareUploadResponse(result.transmissions))
+
+ //TODO UNIFY THE INSTANCE EITHER USE PEERTOPEERINSTANCE OR USE PEERSESSIONMANAGER
+ //TODO UNIFY THE FORMENDVIEW TO USE THE NEW STATE MANAGER ...
}
is PrepareUploadResult.Forbidden -> {
@@ -111,6 +134,8 @@ class SenderViewModel @Inject constructor(
}
}
}
+
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
index 5fb51fbf1..aaee843b1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
@@ -6,6 +6,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
import javax.inject.Singleton
@Module
@@ -23,4 +24,10 @@ object PeerModule {
fun providePeerToPeerManager(): PeerToPeerManager {
return PeerToPeerManager()
}
+
+ @Provides
+ @Singleton
+ fun provideP2PServerState(): P2PServerState {
+ return P2PServerState()
+ }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index 0ce670c43..957ab1c06 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -25,6 +25,7 @@ class ConnectHotspotFragment :
private val viewModel: PeerToPeerViewModel by activityViewModels()
private var isCheckboxChecked = false
+ private val permissionsToRequest = mutableListOf()
@RequiresApi(Build.VERSION_CODES.M)
private val requestPermissionLauncher =
@@ -46,6 +47,7 @@ class ConnectHotspotFragment :
initObservers()
initListeners()
checkAndRequestPermissions()
+ updateInfoOrGetPermission()
}
private fun initObservers() {
@@ -98,7 +100,6 @@ class ConnectHotspotFragment :
@RequiresApi(Build.VERSION_CODES.M)
private fun checkAndRequestPermissions() {
- val permissionsToRequest = mutableListOf()
if (ContextCompat.checkSelfPermission(
baseActivity,
@@ -121,9 +122,14 @@ class ConnectHotspotFragment :
) {
permissionsToRequest.add(ACCESS_NETWORK_STATE)
}
+ }
+ @RequiresApi(Build.VERSION_CODES.M)
+ private fun updateInfoOrGetPermission() {
if (permissionsToRequest.isNotEmpty()) {
- requestPermissionLauncher.launch(permissionsToRequest.toTypedArray())
+ baseActivity.maybeChangeTemporaryTimeout {
+ requestPermissionLauncher.launch(permissionsToRequest.toTypedArray())
+ }
} else {
viewModel.updateNetworkInfo()
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 7f75ac6f6..0f0823a53 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -13,6 +13,7 @@ import org.horizontal.tella.mobile.certificate.CertificateGenerator
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
import org.horizontal.tella.mobile.data.peertopeer.port
import org.horizontal.tella.mobile.databinding.FragmentQrCodeBinding
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
@@ -34,6 +35,9 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
@Inject
lateinit var peerToPeerManager: PeerToPeerManager
+ @Inject
+ lateinit var p2PServerState: P2PServerState
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -68,7 +72,14 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val pin = (100000..999999).random()
val port = port
- peerServerStarterManager.startServer(ip, keyPair, pin, certificate, config)
+ peerServerStarterManager.startServer(
+ ip,
+ keyPair,
+ pin.toString(),
+ certificate,
+ config,
+ p2PServerState
+ )
payload = PeerConnectionPayload(
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 8bfdfb42f..574c2f6d9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -1,10 +1,10 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
-import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.View
+import androidx.fragment.app.activityViewModels
import androidx.fragment.app.setFragmentResultListener
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
@@ -27,7 +27,6 @@ import org.horizontal.tella.mobile.views.activity.camera.CameraActivity.Companio
import org.horizontal.tella.mobile.views.adapters.reports.ReportsFilesRecyclerViewAdapter
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_AUDIO
-import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_FORM_INSTANCE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_VAULT_FILE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.OnNavBckListener
import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
@@ -44,7 +43,6 @@ import org.hzontal.shared_ui.bottomsheet.VaultSheetUtils.showVaultSelectFilesShe
import org.hzontal.shared_ui.utils.DialogUtils
var PREPARE_UPLOAD_ENTRY = "PREPARE_UPLOAD_ENTRY"
-var BUNDLE_PEER_TO_PEER_FORM_INSTANCE = "BUNDLE_PEER_TO_PEER_FORM_INSTANCE"
@AndroidEntryPoint
class PrepareUploadFragment :
@@ -52,8 +50,7 @@ class PrepareUploadFragment :
IReportAttachmentsHandler, OnNavBckListener {
private lateinit var gridLayoutManager: GridLayoutManager
private var isTitleEnabled = false
- private var peerToPeerInstance: PeerToPeerInstance? = null
- private val viewModel: SenderViewModel by viewModels()
+ private val viewModel: SenderViewModel by activityViewModels()
private var disposables =
MyApplication.bus().createCompositeDisposable()
@@ -88,17 +85,7 @@ class PrepareUploadFragment :
exitOrSave()
}
- arguments?.let { bundle ->
- if (bundle.get(BUNDLE_PEER_TO_PEER_FORM_INSTANCE) != null) {
- peerToPeerInstance = bundle.get(BUNDLE_PEER_TO_PEER_FORM_INSTANCE) as PeerToPeerInstance
- bundle.remove(BUNDLE_PEER_TO_PEER_FORM_INSTANCE)
- }
- }
-
- peerToPeerInstance?.let { instance ->
- binding.reportTitleEt.setText(instance.title)
- putFiles(viewModel.mediaFilesToVaultFiles(instance.widgetMediaFiles))
- }
+ //TODO HANDLE THIS IN THE NAVMANAGER
val navBackStackEntry = findNavController().currentBackStackEntry
navBackStackEntry?.savedStateHandle
?.getLiveData("transferRejected")
@@ -111,17 +98,6 @@ class PrepareUploadFragment :
}
}
- viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
- // val transmissionId = response.files.firstOrNull()?.transmissionId
- DialogUtils.showBottomMessage(
- baseActivity,
- getString(R.string.the_receiver_accepted_the_files_transfer),
- false,
- 3000
- )
- // navigate to next screen
- }
-
binding.toolbar.backClickListener = {
BottomSheetUtils.showConfirmSheet(
baseActivity.supportFragmentManager,
@@ -132,7 +108,7 @@ class PrepareUploadFragment :
object : BottomSheetUtils.ActionConfirmed {
override fun accept(isConfirmed: Boolean) {
if (isConfirmed) {
- back()
+ back()
}
}
}
@@ -156,7 +132,7 @@ class PrepareUploadFragment :
}
private fun exitOrSave() {
- navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
private fun showSelectFilesSheet() {
@@ -274,26 +250,31 @@ class PrepareUploadFragment :
private fun initClickListeners(isSubmitEnabled: Boolean) {
binding.sendReportBtn.setOnClickListener {
- binding.sendReportBtn.setOnClickListener {
- if (isSubmitEnabled) {
- val selectedFiles = filesRecyclerViewAdapter.getFiles()
- if (selectedFiles.isNotEmpty()) {
- bundle.putSerializable(
- "selectedFiles",
- ArrayList(selectedFiles)
- ) // assuming VaultFile is Serializable
- // navigate to waiting view
- navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
- } else {
- showToast("No file selected")
- }
+ if (isSubmitEnabled) {
+ val selectedFiles = filesRecyclerViewAdapter.getFiles()
+ if (selectedFiles.isNotEmpty()) {
+ // Fill the PeerToPeerInstance in the ViewModel
+ viewModel.peerToPeerInstance = PeerToPeerInstance(
+ updated = System.currentTimeMillis(),
+ widgetMediaFiles = viewModel.vaultFilesToMediaFiles(selectedFiles),
+ title = binding.reportTitleEt.text.toString()
+ )
+
+ // Optional: add to bundle if still needed elsewhere
+ bundle.putSerializable("selectedFiles", ArrayList(selectedFiles))
+
+ // Navigate
+ navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
} else {
- showSubmitReportErrorSnackBar()
+ showToast("No file selected")
}
+ } else {
+ showSubmitReportErrorSnackBar()
}
}
}
+
private fun showSubmitReportErrorSnackBar() {
val errorRes = R.string.Snackbar_Submit_Files_Error
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
index c0cf40d9b..92b3bcb7e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
@@ -1,45 +1,43 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
import android.os.Bundle
-import android.view.LayoutInflater
import android.view.View
-import android.view.ViewGroup
+import androidx.fragment.app.activityViewModels
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.ReportsFormEndView
+import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
+import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
class UploadFilesFragment :
BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- return super.onCreateView(inflater, container, savedInstanceState)
- }
+ private val viewModel: SenderViewModel by activityViewModels()
+ protected lateinit var endView: PeerToPeerEndView
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ showFormEndView()
+ }
private fun showFormEndView() {
- /* if (reportInstance == null) {
- return
- }
-
- reportInstance?.let { reportFormInstance ->
-
- endView = ReportsFormEndView(
- activity,
- reportFormInstance.title,
- reportFormInstance.description,
- )
- endView.setInstance(
- reportFormInstance, MyApplication.isConnectedToInternet(baseActivity), false
- )
- binding.endViewContainer.removeAllViews()
- binding.endViewContainer.addView(endView)
- endView.clearPartsProgress(reportFormInstance)
- }*/
+ if (viewModel.peerToPeerInstance == null) {
+ return
+ }
+
+ viewModel.peerToPeerInstance?.let { peerInstance ->
+
+ endView = PeerToPeerEndView(
+ baseActivity,
+ peerInstance.title,
+ )
+ endView.setInstance(
+ peerInstance, MyApplication.isConnectedToInternet(baseActivity), false
+ )
+ binding.endViewContainer.removeAllViews()
+ binding.endViewContainer.addView(endView)
+ endView.clearPartsProgress(peerInstance)
+ }
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
index 6570e8100..a29057b6a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
@@ -9,24 +9,26 @@ import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
+import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
*/
class WaitingSenderFragment :
BaseBindingFragment(FragmentWaitingBinding::inflate) {
- private val viewModelSender: SenderViewModel by activityViewModels()
+ private val viewModel: SenderViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.toolbar.setStartTextTitle(getString(R.string.send_files))
binding.waitingText.text = getString(R.string.waiting_for_the_recipient_to_accept_files)
- val selectedFiles = arguments?.getSerializable("selectedFiles") as? List ?: emptyList()
- viewModelSender.prepareUploadsFromVaultFiles(selectedFiles)
+ val selectedFiles =
+ arguments?.getSerializable("selectedFiles") as? List ?: emptyList()
+ viewModel.prepareUploadsFromVaultFiles(selectedFiles)
binding.toolbar.backClickListener = {
navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
- viewModelSender.prepareRejected.observe(viewLifecycleOwner) { event ->
+ viewModel.prepareRejected.observe(viewLifecycleOwner) { event ->
event.getContentIfNotHandled()?.let { wasRejected ->
if (wasRejected) {
findNavController().previousBackStackEntry
@@ -36,5 +38,10 @@ class WaitingSenderFragment :
}
}
}
+
+
+ viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
+ navManager().navigateFromWaitingSenderFragmentToUploadFilesFragment()
+ }
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
new file mode 100644
index 000000000..8521e7378
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
@@ -0,0 +1,246 @@
+package org.horizontal.tella.mobile.views.fragment.uwazi.widgets;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.google.android.material.progressindicator.LinearProgressIndicator;
+import com.hzontal.utils.MediaFile;
+
+import org.horizontal.tella.mobile.R;
+import org.horizontal.tella.mobile.domain.entity.EntityStatus;
+import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile;
+import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus;
+import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance;
+import org.horizontal.tella.mobile.util.FileUtil;
+import org.horizontal.tella.mobile.util.Util;
+import org.hzontal.shared_ui.submission.SubmittingItem;
+
+import java.util.Objects;
+
+/**
+ * Created by wafa on 9/7/2025.
+ */
+public class PeerToPeerEndView extends FrameLayout {
+ LinearLayout partsListView;
+ TextView titleView;
+ TextView formStatusTextView;
+ TextView formSizeView;
+ String title;
+ LinearProgressIndicator totalProgress;
+ long formSize = 0L;
+ private PeerToPeerInstance instance;
+ private boolean previewUploaded;
+
+ public PeerToPeerEndView(Context context, String title) {
+ super(context);
+ inflate(context, R.layout.reports_form_end_view, this);
+
+ this.title = title;
+
+ titleView = findViewById(R.id.title);
+ titleView.setText(title);
+
+ totalProgress = findViewById(R.id.totalProgress);
+ formSizeView = findViewById(R.id.formSize);
+
+ formStatusTextView = findViewById(R.id.form_status);
+ }
+
+ public void setInstance(@NonNull PeerToPeerInstance instance, boolean offline, boolean previewUploaded) {
+ this.instance = instance;
+ this.previewUploaded = previewUploaded;
+ refreshInstance(offline);
+ }
+
+ public void refreshInstance(boolean offline) {
+ if (this.instance == null) {
+ return;
+ }
+
+ TextView formNameView = findViewById(R.id.title);
+
+ formNameView.setText(Objects.requireNonNull(instance.getTitle()));
+
+ partsListView = findViewById(R.id.formPartsList);
+ partsListView.removeAllViews();
+
+ for (FormMediaFile mediaFile : instance.getWidgetMediaFiles()) {
+ partsListView.addView(createFormMediaFileItemView(mediaFile, offline));
+ formSize += mediaFile.size;
+ }
+ setFormSizeLabel(instance, 0);
+ uploadProgressVisibity(instance, offline);
+ setUploadProgress(instance, 0);
+ }
+
+ void setFormSizeLabel(@NonNull PeerToPeerInstance instance, int percent) {
+ String title;
+ if (instance.getWidgetMediaFiles().isEmpty()) {
+ title = getStatusLabel(instance.getStatus());
+ formSizeView.setText(title);
+ return;
+ }
+ switch (instance.getStatus()) {
+ case SUBMITTED:
+ title = getStatusLabel(instance.getStatus()) + "\n" +
+ getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
+ instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
+ FileUtil.getFileSizeString(formSize);
+ break;
+ case PAUSED:
+ title = getStatusLabel(instance.getStatus()) + "\n" +
+ getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
+ instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
+ getTotalUploadedSize(instance) + "/" + FileUtil.getFileSizeString(formSize);
+ break;
+ case FINALIZED:
+ case SUBMISSION_PENDING:
+ case SUBMISSION_ERROR:
+ title = getStatusLabel(instance.getStatus()) + "\n" +
+ getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
+ instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
+ getTotalUploadedSize(instance) + "/" + FileUtil.getFileSizeString(formSize) + " " +
+ getResources().getString(R.string.File_Uploaded);
+ break;
+ default:
+ title = percent + "% " + getResources().getString(R.string.File_Uploaded) + "\n" +
+ getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
+ instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
+ getTotalUploadedSize(instance) + "/" + FileUtil.getFileSizeString(formSize) + " " +
+ getResources().getString(R.string.File_Uploaded);
+ break;
+ }
+
+ formSizeView.setText(title);
+ }
+
+
+ String getStatusLabel(EntityStatus status) {
+ String title = "";
+ if (status == EntityStatus.SUBMITTED) {
+ title = getResources().getString(R.string.File_Uploaded_on) + " " + Util.getDateTimeString(instance.getUpdated());
+ } else if (status == EntityStatus.PAUSED) {
+ title = getResources().getString(R.string.Paused_Report);
+ } else if (status == EntityStatus.FINALIZED || instance.getStatus() == EntityStatus.SUBMISSION_PENDING || instance.getStatus() == EntityStatus.SUBMISSION_ERROR) {
+ title = getResources().getString(R.string.Report_Waiting_For_Connection);
+ }
+ return title;
+ }
+
+ private void uploadProgressVisibity(PeerToPeerInstance instance, Boolean isOnline) {
+ if (!isOnline || instance.getWidgetMediaFiles().isEmpty()) {
+ totalProgress.setVisibility(GONE);
+ return;
+ }
+
+ if (instance.getStatus() == EntityStatus.SUBMITTED) {
+ totalProgress.setVisibility(GONE);
+ } else {
+ totalProgress.setVisibility(VISIBLE);
+ }
+ }
+
+ public void setUploadProgress(PeerToPeerInstance instance, float pct) {
+ if (pct < 0 || pct > 1) {
+ return;
+ }
+
+ int percentComplete;
+
+ if (instance.getWidgetMediaFiles().size() > 1) {
+ percentComplete = getTotalUploadedSizePercent(instance);
+ } else {
+ percentComplete = (int) (pct * 100);
+ }
+
+ for (FormMediaFile mediaFile : instance.getWidgetMediaFiles()) {
+ if (mediaFile.status == FormMediaFileStatus.SUBMITTED) {
+ SubmittingItem item = partsListView.findViewWithTag(mediaFile.getVaultFile().id);
+ item.setPartUploaded();
+ }
+ }
+
+ //Timber.d("***Test*** PCT " + pct + "\n getTotalUploadedSize " + getTotalUploadedSize(instance) + "\n FormSize " + formSize + "\n percentComplete " + percentComplete + " \n Math.round(percentComplete) " + Math.toIntExact(percentComplete));
+ totalProgress.setProgressCompat(percentComplete, true);
+ setFormSizeLabel(instance, percentComplete);
+ }
+
+ private int getTotalUploadedSizePercent(PeerToPeerInstance instance) {
+ int totalUploadedSize = 0;
+ for (FormMediaFile formMediaFile : instance.getWidgetMediaFiles()) {
+ totalUploadedSize += formMediaFile.uploadedSize;
+ }
+ if (totalUploadedSize > 0) {
+ float percent = ((float) (totalUploadedSize * 1.0) / formSize);
+ return Math.round(percent * 100);
+
+ } else {
+ return 0;
+ }
+ }
+
+ private String getTotalUploadedSize(PeerToPeerInstance instance) {
+ long totalUploadedSize = 0;
+ for (FormMediaFile formMediaFile : instance.getWidgetMediaFiles()) {
+ totalUploadedSize += formMediaFile.uploadedSize;
+ }
+ return FileUtil.getFileSize(totalUploadedSize);
+ }
+
+ public void clearPartsProgress(PeerToPeerInstance instance) {
+ setPartsCleared(instance);
+ }
+
+
+ private View createFormMediaFileItemView(@NonNull FormMediaFile mediaFile, boolean offline) {
+
+ SubmittingItem item = new SubmittingItem(getContext(), null, 0);
+ ImageView thumbView = item.findViewById(R.id.fileThumb);
+ item.setTag(mediaFile.getPartName());
+
+ item.setPartName(mediaFile.name);
+ item.setPartSize(mediaFile.size);
+
+ if (MediaFile.INSTANCE.isImageFileType(mediaFile.mimeType) || (MediaFile.INSTANCE.isVideoFileType(mediaFile.mimeType))) {
+ Glide.with(getContext())
+ .load(mediaFile.thumb)
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
+ .skipMemoryCache(true)
+ .into(thumbView);
+ } else if (MediaFile.INSTANCE.isAudioFileType(mediaFile.mimeType)) {
+ item.setPartIcon(R.drawable.ic_headset_white_24dp);
+ } else {
+ item.setPartIcon(R.drawable.ic_attach_file_white_24dp);
+ }
+
+ if (mediaFile.status == FormMediaFileStatus.SUBMITTED || previewUploaded) {
+ item.setPartUploaded();
+ } else {
+ item.setPartPrepared(offline);
+ }
+
+ return item;
+ }
+
+ private void setPartsCleared(PeerToPeerInstance instance) {
+ for (FormMediaFile mediaFile : instance.getWidgetMediaFiles()) {
+ SubmittingItem item = partsListView.findViewWithTag(mediaFile.getVaultFile().id);
+
+ if (instance.getStatus() == EntityStatus.SUBMITTED) {
+ item.setPartUploaded();
+ } else {
+ item.setPartCleared();
+ }
+ }
+ }
+}
+
+
diff --git a/mobile/src/main/res/layout/fragment_send_report.xml b/mobile/src/main/res/layout/fragment_send_report.xml
index ed3455116..8ebbf7bb1 100644
--- a/mobile/src/main/res/layout/fragment_send_report.xml
+++ b/mobile/src/main/res/layout/fragment_send_report.xml
@@ -32,22 +32,19 @@
app:startTitle="@string/Reports_Title_Screen" />
+ app:layout_constraintStart_toStartOf="parent" />
+ app:startTitle="@string/sending_files" />
-
+ />
+ android:label="WaitingSenderFragment" >
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index bd0a26dd8..cefc0ca6a 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1052,5 +1052,6 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
"The receiver accepted the files transfer "
Recipient rejected the files.
Receiving and encrypting files
+ Sending files
Send files
From 5997358b63fe7ca0ee7beef7ab650d1cbbdf5dd8 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Thu, 10 Jul 2025 17:56:06 +0100
Subject: [PATCH 062/153] WIP unify client/server state
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 9 +--
.../data/peertopeer/TellaPeerToPeerServer.kt | 21 +++---
.../managers/PeerServerStarterManager.kt | 6 +-
.../data/peertopeer/model/P2PFileStatus.kt | 8 +++
.../data/peertopeer/model/P2PServerState.kt | 66 -------------------
.../data/peertopeer/model/P2PSession.kt | 13 ++++
.../data/peertopeer/model/P2PSharedState.kt | 13 ++++
.../data/peertopeer/model/ProgressFile.kt | 11 ++++
.../data/peertopeer/model/SessionStatus.kt | 8 +++
.../entity/peertopeer/PeerToPeerInstance.kt | 3 -
.../fragment/peertopeer/PeerSessionManager.kt | 29 --------
.../peertopeer/PeerToPeerViewModel.kt | 14 ++--
.../fragment/peertopeer/SenderViewModel.kt | 17 ++---
.../fragment/peertopeer/di/PeerModule.kt | 6 +-
.../receipentflow/QRCodeFragment.kt | 11 +++-
.../RecipientVerificationFragment.kt | 9 +--
.../receipentflow/ShowDeviceInfoFragment.kt | 19 +++---
.../senderflow/PrepareUploadFragment.kt | 10 +--
.../senderflow/ScanQrCodeFragment.kt | 4 ++
.../SenderManualConnectionFragment.kt | 22 +------
.../senderflow/SenderVerificationFragment.kt | 20 ++----
.../uwazi/widgets/PeerToPeerEndView.java | 3 +-
.../hzontal/shared_ui/buttons/RoundButton.kt | 1 +
.../main/res/layout/layout_round_button.xml | 1 +
24 files changed, 125 insertions(+), 199 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/SessionStatus.kt
delete mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 54c0dadc6..92ae3c4a9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -19,7 +19,6 @@ import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerSessionManager
import org.json.JSONObject
import timber.log.Timber
import java.security.SecureRandom
@@ -27,11 +26,13 @@ import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.UUID
import java.util.concurrent.TimeUnit
+import javax.inject.Inject
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
-class TellaPeerToPeerClient {
+class TellaPeerToPeerClient @Inject constructor(){
+
private fun getClientWithFingerprintValidation(expectedFingerprint: String): OkHttpClient {
val trustManager = object : X509TrustManager {
@@ -83,7 +84,7 @@ class TellaPeerToPeerClient {
return@withContext try {
client.newCall(request).execute().use { response ->
- val body = response.body?.string().orEmpty()
+ val body = response.body.string().orEmpty()
if (response.isSuccessful) {
return@use parseSessionIdFromResponse(body)
@@ -178,7 +179,7 @@ class TellaPeerToPeerClient {
val response = Json.decodeFromString(body)
response.files.forEach {
- PeerSessionManager.saveTransmissionId(it.id, it.transmissionId)
+ // PeerSessionManager.saveTransmissionId(it.id, it.transmissionId)
}
PrepareUploadResult.Success(response.files)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 9642664c5..60f92cf22 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -21,9 +21,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
-import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
-import org.horizontal.tella.mobile.data.peertopeer.model.ReceivingFile
+import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.domain.peertopeer.FileInfo
@@ -48,7 +48,7 @@ class TellaPeerToPeerServer(
private val certificate: X509Certificate,
private val keyStoreConfig: KeyStoreConfig,
private val peerToPeerManager: PeerToPeerManager,
- private val p2PServerState: P2PServerState
+ private val p2PSharedState: P2PSharedState
) : TellaServer {
private var serverSession: PeerResponse? = null
private var engine: ApplicationEngine? = null
@@ -89,9 +89,8 @@ class TellaPeerToPeerServer(
}
post(PeerApiRoutes.PING) {
- val hash = CertificateUtils.getPublicKeyHash(certificate)
CoroutineScope(Dispatchers.IO).launch {
- peerToPeerManager.notifyClientConnected(hash)
+ peerToPeerManager.notifyClientConnected(p2PSharedState.hash)
}
call.respondText("pong", status = HttpStatusCode.OK)
}
@@ -140,10 +139,6 @@ class TellaPeerToPeerServer(
}
launch {
- p2PServerState.apply {
- pin = this@TellaPeerToPeerServer.pin
-
- }
PeerEventManager.emitRegistrationSuccess()
}
@@ -173,13 +168,13 @@ class TellaPeerToPeerServer(
call.respond(HttpStatusCode.InternalServerError, "Missing session")
return@post
}
-
- val session = P2PSession(sessionId = sessionId, title = request.title)
+ p2PSharedState.sessionId = sessionId
+ val session = P2PSession(title = request.title)
val responseFiles = request.files.map { file ->
val transmissionId = UUID.randomUUID().toString()
- val receivingFile = ReceivingFile(
+ val receivingFile = ProgressFile(
file = file,
transmissionId = transmissionId
)
@@ -191,7 +186,7 @@ class TellaPeerToPeerServer(
)
}
- p2PServerState.session = session
+ p2PSharedState.session = session
call.respond(
HttpStatusCode.OK,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
index 6449bc74f..3dc6c0b53 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
@@ -4,7 +4,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerServer
-import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import java.security.KeyPair
import java.security.cert.X509Certificate
@@ -23,7 +23,7 @@ class PeerServerStarterManager @Inject constructor(
pin: String,
cert: X509Certificate,
config: KeyStoreConfig,
- p2PServerState: P2PServerState,
+ p2PSharedState: P2PSharedState,
) {
if (server == null) {
server = TellaPeerToPeerServer(
@@ -33,7 +33,7 @@ class PeerServerStarterManager @Inject constructor(
certificate = cert,
keyStoreConfig = config,
peerToPeerManager = peerToPeerManager,
- p2PServerState = p2PServerState
+ p2PSharedState = p2PSharedState
)
server?.start()
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
new file mode 100644
index 000000000..1a3f7d1c2
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
@@ -0,0 +1,8 @@
+package org.horizontal.tella.mobile.data.peertopeer.model
+
+enum class P2PFileStatus {
+ QUEUE,
+ SENDING,
+ FAILED,
+ FINISHED
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
deleted file mode 100644
index 2d5c0ca4a..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PServerState.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.horizontal.tella.mobile.data.peertopeer.model
-
-import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
-
-// --- ENUMS ---
-
-enum class P2PFileStatus {
- QUEUE,
- SENDING,
- FAILED,
- FINISHED
-}
-
-enum class SessionStatus {
- WAITING,
- SENDING,
- FINISHED,
- FINISHED_WITH_ERRORS
-}
-
-data class ReceivingFile(
- var file: P2PFile,
- var status: P2PFileStatus = P2PFileStatus.QUEUE,
- var transmissionId: String? = null,
- var path: String? = null,
- var bytesReceived: Int = 0
-)
-
-class P2PSession(
- var sessionId: String,
- var status: SessionStatus = SessionStatus.WAITING,
- var files: MutableMap = mutableMapOf(),
- var title: String? = null
-) {
- val isActive: Boolean
- get() = status == SessionStatus.WAITING || status == SessionStatus.SENDING
-
- val hasFiles: Boolean
- get() = files.isNotEmpty()
-}
-
-class P2PServerState(
- var pin: String? = null,
- var session: P2PSession? = null,
- private var failedAttempts: Int = 0,
- //TODO ASK DHEKRA ABOIUT THIS
- private var isUsingManualConnection: Boolean = false
-) {
- private val maxFailedAttempts = 3
-
- val hasReachedMaxAttempts: Boolean
- get() = failedAttempts >= maxFailedAttempts
-
- fun incrementFailedAttempts() {
- failedAttempts++
- }
-
- fun reset() {
- pin = null
- session = null
- failedAttempts = 0
- isUsingManualConnection = false
- }
-
- fun getFailedAttempts(): Int = failedAttempts
-}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
new file mode 100644
index 000000000..cbc81b86d
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
@@ -0,0 +1,13 @@
+package org.horizontal.tella.mobile.data.peertopeer.model
+
+class P2PSession(
+ var status: SessionStatus = SessionStatus.WAITING,
+ var files: MutableMap = mutableMapOf(),
+ var title: String? = null
+) {
+ val isActive: Boolean
+ get() = status == SessionStatus.WAITING || status == SessionStatus.SENDING
+
+ val hasFiles: Boolean
+ get() = files.isNotEmpty()
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
new file mode 100644
index 000000000..2374fcf46
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
@@ -0,0 +1,13 @@
+package org.horizontal.tella.mobile.data.peertopeer.model
+
+class P2PSharedState(
+ var ip: String = "",
+ var port: String = "",
+ var sessionId: String = "",
+ //THE HASH IS THE SAME EXPECTED FINGER PRINT
+ var hash: String = "",
+ var pin: String? = null,
+ var session: P2PSession? = null,
+ var failedAttempts: Int = 0,
+ var isUsingManualConnection: Boolean = false
+)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt
new file mode 100644
index 000000000..760eff5a9
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt
@@ -0,0 +1,11 @@
+package org.horizontal.tella.mobile.data.peertopeer.model
+
+import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
+
+data class ProgressFile(
+ var file: P2PFile,
+ var status: P2PFileStatus = P2PFileStatus.QUEUE,
+ var transmissionId: String? = null,
+ var path: String? = null,
+ var bytesTransferred: Int = 0
+)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/SessionStatus.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/SessionStatus.kt
new file mode 100644
index 000000000..dd048ae37
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/SessionStatus.kt
@@ -0,0 +1,8 @@
+package org.horizontal.tella.mobile.data.peertopeer.model
+
+enum class SessionStatus {
+ WAITING,
+ SENDING,
+ FINISHED,
+ FINISHED_WITH_ERRORS
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
index 2312e005a..18d539ed8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/entity/peertopeer/PeerToPeerInstance.kt
@@ -5,12 +5,9 @@ import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
class PeerToPeerInstance(
- var id: Long = -1,
- var updated: Long = 0,
var status: EntityStatus = EntityStatus.UNKNOWN,
var widgetMediaFiles: List = mutableListOf(),
var formPartStatus: FormMediaFileStatus = FormMediaFileStatus.UNKNOWN,
var title: String = "",
- var current: Long = 0,
var sessionID: String = ""
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
deleted file mode 100644
index 9e6b6b346..000000000
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerSessionManager.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer
-
-//TODO CHECK IF WE SHOULD REMOVE THIS
-data class PeerConnectionInfo(
- val ip: String = "",
- val port: String = "",
- val expectedFingerprint: String = "",
- val sessionId: String = "",
- val hash: String = "",
- val pin: Int = 0,
-)
-
-object PeerSessionManager {
- private var connectionInfo: PeerConnectionInfo? = null
-
- fun saveConnectionInfo(
- ip: String,
- port: String,
- expectedFingerprint: String,
- sessionId: String
- ) {
- connectionInfo = PeerConnectionInfo(ip, port, expectedFingerprint, sessionId)
- }
-
- fun getConnectionInfo(): PeerConnectionInfo? = connectionInfo
-
- fun isSessionValid(): Boolean = connectionInfo != null
-
-}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 1fd34f1ce..29a63c125 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -16,6 +16,7 @@ import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
@@ -29,7 +30,8 @@ import javax.inject.Inject
class PeerToPeerViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val peerClient: TellaPeerToPeerClient,
- peerToPeerManager: PeerToPeerManager
+ peerToPeerManager: PeerToPeerManager,
+ val p2PState: P2PSharedState
) : ViewModel() {
var isManualConnection: Boolean = true // default is manual
@@ -41,8 +43,6 @@ class PeerToPeerViewModel @Inject constructor(
val getHashSuccess: LiveData get() = _getHashSuccess
private val _getHashError = MutableLiveData()
val getHashError: LiveData get() = _getHashError
- private val _sessionInfo = MutableStateFlow(null)
- val sessionInfo: StateFlow = _sessionInfo
val clientHash = peerToPeerManager.clientConnected
private val _registrationServerSuccess = MutableLiveData()
val registrationServerSuccess: LiveData = _registrationServerSuccess
@@ -102,7 +102,10 @@ class PeerToPeerViewModel @Inject constructor(
viewModelScope.launch {
when (val result = peerClient.registerPeerDevice(ip, port, hash, pin)) {
is RegisterPeerResult.Success -> {
- PeerSessionManager.saveConnectionInfo(ip, port, hash, result.sessionId)
+ with(p2PState) {
+ this.sessionId = result.sessionId
+ }
+
_registrationSuccess.postValue(true)
}
@@ -178,7 +181,4 @@ class PeerToPeerViewModel @Inject constructor(
}
- fun setPeerSessionInfo(info: PeerConnectionInfo) {
- _sessionInfo.value = info
- }
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index a7a4db0bb..6f23a20ff 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -14,6 +14,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
@@ -27,7 +28,8 @@ import javax.inject.Inject
@HiltViewModel
class SenderViewModel @Inject constructor(
- private val peerClient: TellaPeerToPeerClient
+ private val peerClient: TellaPeerToPeerClient,
+ var p2PSharedState: P2PSharedState
) : ViewModel() {
private val _prepareResults = MutableLiveData()
val prepareResults: LiveData = _prepareResults
@@ -79,22 +81,17 @@ class SenderViewModel @Inject constructor(
files: List,
title: String = "Title of the report"
) {
- val info = PeerSessionManager.getConnectionInfo() ?: run {
- Timber.e("Connection info missing")
- return
- }
viewModelScope.launch {
when (val result = peerClient.prepareUpload(
- ip = info.ip,
- port = info.port,
- expectedFingerprint = info.expectedFingerprint,
+ ip = p2PSharedState.ip,
+ port = p2PSharedState.port,
title = title,
files = files,
- sessionId = info.sessionId
+ sessionId = p2PSharedState.sessionId
)) {
is PrepareUploadResult.Success -> {
- peerToPeerInstance?.sessionID = info.sessionId
+ peerToPeerInstance?.sessionID = p2PSharedState.sessionId
val fileInfoMap = result.transmissions.associateBy { it.id }
peerToPeerInstance?.widgetMediaFiles?.forEach { mediaFile ->
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
index aaee843b1..b2c19475e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
@@ -6,7 +6,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
-import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import javax.inject.Singleton
@Module
@@ -27,7 +27,7 @@ object PeerModule {
@Provides
@Singleton
- fun provideP2PServerState(): P2PServerState {
- return P2PServerState()
+ fun provideP2PServerState(): P2PSharedState {
+ return P2PSharedState()
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 0f0823a53..2cc88d231 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -13,7 +13,7 @@ import org.horizontal.tella.mobile.certificate.CertificateGenerator
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
-import org.horizontal.tella.mobile.data.peertopeer.model.P2PServerState
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.port
import org.horizontal.tella.mobile.databinding.FragmentQrCodeBinding
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
@@ -36,7 +36,7 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
lateinit var peerToPeerManager: PeerToPeerManager
@Inject
- lateinit var p2PServerState: P2PServerState
+ lateinit var p2PSharedState: P2PSharedState
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -72,13 +72,18 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
val pin = (100000..999999).random()
val port = port
+ p2PSharedState.pin = pin.toString()
+ p2PSharedState.port = port.toString()
+ p2PSharedState.hash = certHash
+ p2PSharedState.ip = ip
+
peerServerStarterManager.startServer(
ip,
keyPair,
pin.toString(),
certificate,
config,
- p2PServerState
+ p2PSharedState
)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 9234e6a34..07b61e60b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -50,12 +50,9 @@ class RecipientVerificationFragment :
}
private fun initObservers() {
- lifecycleScope.launchWhenStarted {
- viewModel.sessionInfo.collect { session ->
- binding.hashContentTextView.text = session?.hash?.formatHash()
- }
- }
- viewModel.isManualConnection = true
+ binding.hashContentTextView.text = viewModel.p2PState.hash.formatHash()
+
+ viewModel.p2PState.isUsingManualConnection = true
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 559e8872e..2efe8c854 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -9,7 +9,6 @@ import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.databinding.ShowDeviceInfoLayoutBinding
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
class ShowDeviceInfoFragment :
@@ -42,15 +41,13 @@ class ShowDeviceInfoFragment :
private fun initObservers() {
lifecycleScope.launch {
- viewModel.clientHash.collect { hash ->
- viewModel.setPeerSessionInfo(
- PeerConnectionInfo(
- ip = payload?.ipAddress.toString(),
- port = payload?.port.toString(),
- pin = payload?.pin?.toInt()!!,
- hash = hash
- )
- )
+ viewModel.clientHash.collect { clientHash ->
+ with(viewModel.p2PState) {
+ ip = payload?.ipAddress.toString()
+ port = payload?.port.toString()
+ pin = payload?.pin
+ hash = clientHash
+ }
navManager().navigateFromDeviceInfoScreenTRecipientVerificationScreen()
}
}
@@ -58,7 +55,7 @@ class ShowDeviceInfoFragment :
viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
// Navigate to the next screen
- // bundle.putBoolean("isSender", false)
+ // bundle.putBoolean("isSender", false)
navManager().navigateFromWaitingReceiverFragmentToRecipientSuccessFragment()
// reset the LiveData state if we want to consume event once
viewModel.resetRegistrationState()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 574c2f6d9..279b28307 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -254,11 +254,11 @@ class PrepareUploadFragment :
val selectedFiles = filesRecyclerViewAdapter.getFiles()
if (selectedFiles.isNotEmpty()) {
// Fill the PeerToPeerInstance in the ViewModel
- viewModel.peerToPeerInstance = PeerToPeerInstance(
- updated = System.currentTimeMillis(),
- widgetMediaFiles = viewModel.vaultFilesToMediaFiles(selectedFiles),
- title = binding.reportTitleEt.text.toString()
- )
+ /* viewModel.peerToPeerInstance = PeerToPeerInstance(
+ updated = System.currentTimeMillis(),
+ widgetMediaFiles = viewModel.vaultFilesToMediaFiles(selectedFiles),
+ title = binding.reportTitleEt.text.toString()
+ )*/
// Optional: add to bundle if still needed elsewhere
bundle.putSerializable("selectedFiles", ArrayList(selectedFiles))
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 6691a6461..7626a6864 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -60,6 +60,10 @@ class ScanQrCodeFragment :
try {
val payload = Gson().fromJson(qrContent, PeerConnectionPayload::class.java)
+ viewModel.p2PState.pin = payload.pin
+ viewModel.p2PState.port = payload.port.toString()
+ viewModel.p2PState.hash = payload.certificateHash
+ viewModel.p2PState.ip = payload.ipAddress
viewModel.startRegistration(
ip = payload.ipAddress,
port = payload.port.toString(),
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index e16e51cce..e9bbbe3a5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -7,10 +7,10 @@ import androidx.fragment.app.activityViewModels
import com.hzontal.tella_locking_ui.common.extensions.onChange
import org.horizontal.tella.mobile.databinding.SenderManualConnectionBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
import org.hzontal.shared_ui.bottomsheet.KeyboardUtil
+//TODO SHOW ERRORS IN THE BOTTOM
class SenderManualConnectionFragment :
BaseBindingFragment(SenderManualConnectionBinding::inflate) {
@@ -70,17 +70,6 @@ class SenderManualConnectionFragment :
binding.toolbar.backClickListener = { nav().popBackStack() }
binding.backBtn.setOnClickListener { nav().popBackStack() }
binding.nextBtn.setOnClickListener {
- val ip = binding.ipAddress.text.toString()
- val pin = binding.pin.text.toString()
- val port = binding.port.text.toString()
- viewModel.setPeerSessionInfo(
- PeerConnectionInfo(
- ip = ip,
- port = port,
- pin = pin.toInt()
- )
- ) // Store values
-
viewModel.handleCertificate(
ip = binding.ipAddress.text.toString(),
port = binding.port.text.toString(),
@@ -92,15 +81,6 @@ class SenderManualConnectionFragment :
private fun initObservers() {
viewModel.getHashSuccess.observe(viewLifecycleOwner) { hash ->
bundle.putString("payload", hash)
- viewModel.setPeerSessionInfo(
- PeerConnectionInfo(
- ip = binding.ipAddress.text.toString(),
- port = binding.port.text.toString(),
- pin = binding.pin.text.toString().toInt(),
- hash = hash
- )
- )
-
navManager().navigateFromSenderManualConnectionToConnectManuallyVerification()
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index f5b2b9dc0..47cf3f36b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -9,14 +9,12 @@ import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterMan
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
import org.horizontal.tella.mobile.util.formatHash
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerConnectionInfo
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
import javax.inject.Inject
class SenderVerificationFragment :
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
- private lateinit var peerConnectionInfo: PeerConnectionInfo
@Inject
lateinit var peerServerStarterManager: PeerServerStarterManager
@@ -36,21 +34,15 @@ class SenderVerificationFragment :
}
private fun initListeners() {
- lifecycleScope.launchWhenStarted {
- viewModel.sessionInfo.collect { session ->
- if (session != null) {
- peerConnectionInfo = session
- }
- binding.hashContentTextView.text = session?.hash?.formatHash()
- }
- }
+
+ binding.hashContentTextView.text = viewModel.p2PState.hash.formatHash()
binding.confirmAndConnectBtn.setOnClickListener {
viewModel.startRegistration(
- ip = peerConnectionInfo.ip,
- port = peerConnectionInfo.port,
- hash = peerConnectionInfo.hash,
- pin = peerConnectionInfo.pin.toString()
+ ip = viewModel.p2PState.ip,
+ port = viewModel.p2PState.port,
+ hash = viewModel.p2PState.hash,
+ pin = viewModel.p2PState.pin.toString()
)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
index 8521e7378..4a5205929 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
@@ -126,7 +126,8 @@ void setFormSizeLabel(@NonNull PeerToPeerInstance instance, int percent) {
String getStatusLabel(EntityStatus status) {
String title = "";
if (status == EntityStatus.SUBMITTED) {
- title = getResources().getString(R.string.File_Uploaded_on) + " " + Util.getDateTimeString(instance.getUpdated());
+ title = "";
+ //getResources().getString(R.string.File_Uploaded_on) + " " + Util.getDateTimeString(instance.getUpdated());
} else if (status == EntityStatus.PAUSED) {
title = getResources().getString(R.string.Paused_Report);
} else if (status == EntityStatus.FINALIZED || instance.getStatus() == EntityStatus.SUBMISSION_PENDING || instance.getStatus() == EntityStatus.SUBMISSION_ERROR) {
diff --git a/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt b/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt
index 075bc0200..a7c654873 100644
--- a/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt
+++ b/shared-ui/src/main/java/org/hzontal/shared_ui/buttons/RoundButton.kt
@@ -128,6 +128,7 @@ class RoundButton @JvmOverloads constructor(
else ContextCompat.getDrawable(context, R.drawable.bg_information_button)
}
+ //TODO FIX TEXT ALLCAPS EVERY WHERE
private fun setTextCaps(isTextAllCaps: Boolean) {
binding.sheetTextView.isAllCaps = isTextAllCaps
}
diff --git a/shared-ui/src/main/res/layout/layout_round_button.xml b/shared-ui/src/main/res/layout/layout_round_button.xml
index 78b3fe12b..d1adb1530 100644
--- a/shared-ui/src/main/res/layout/layout_round_button.xml
+++ b/shared-ui/src/main/res/layout/layout_round_button.xml
@@ -20,6 +20,7 @@
android:textColor="@color/wa_white"
android:fontFamily="@font/open_sans"
android:textSize="18sp"
+ android:textAllCaps="true"
/>
\ No newline at end of file
From 0ab3c7c92a7d6381b30525ecabf9ae596f8a7195 Mon Sep 17 00:00:00 2001
From: wafa
Date: Fri, 11 Jul 2025 14:41:12 +0100
Subject: [PATCH 063/153] wip fix state
---
.../mobile/data/peertopeer/model/P2PSharedState.kt | 14 +++++++++++++-
.../fragment/peertopeer/PeerToPeerViewModel.kt | 5 +++++
.../views/fragment/peertopeer/SenderViewModel.kt | 5 +++++
.../receipentflow/ShowDeviceInfoFragment.kt | 6 +++---
4 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
index 2374fcf46..dca849d6b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
@@ -10,4 +10,16 @@ class P2PSharedState(
var session: P2PSession? = null,
var failedAttempts: Int = 0,
var isUsingManualConnection: Boolean = false
-)
+) {
+
+ fun clear() {
+ ip = ""
+ port = ""
+ sessionId = ""
+ hash = ""
+ pin = null
+ session = null
+ failedAttempts = 0
+ isUsingManualConnection = false
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 29a63c125..92e8f8712 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -181,4 +181,9 @@ class PeerToPeerViewModel @Inject constructor(
}
+ override fun onCleared() {
+ super.onCleared()
+ p2PState.clear()
+ }
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 6f23a20ff..197f4ff86 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -86,6 +86,7 @@ class SenderViewModel @Inject constructor(
when (val result = peerClient.prepareUpload(
ip = p2PSharedState.ip,
port = p2PSharedState.port,
+ expectedFingerprint = p2PSharedState.hash,
title = title,
files = files,
sessionId = p2PSharedState.sessionId
@@ -132,6 +133,10 @@ class SenderViewModel @Inject constructor(
}
}
+ override fun onCleared() {
+ super.onCleared()
+ p2PSharedState.clear()
+ }
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 2efe8c854..152537624 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -29,9 +29,9 @@ class ShowDeviceInfoFragment :
}
private fun initView() {
- binding.connectCode.setRightText(payload?.ipAddress)
- binding.pin.setRightText(payload?.pin)
- binding.port.setRightText(payload?.port.toString())
+ binding.connectCode.setRightText(viewModel.p2PState.ip)
+ binding.pin.setRightText(viewModel.p2PState.pin)
+ binding.port.setRightText(viewModel.p2PState.port)
}
private fun initListeners() {
From 74e1a661d01ab593b762e55f15076e3e4e16888f Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Fri, 11 Jul 2025 17:57:56 +0100
Subject: [PATCH 064/153] Fix logic with the new state
---
.../peertopeer/PeerToPeerViewModel.kt | 3 +-
.../RecipientVerificationFragment.kt | 52 ++++++-----
.../senderflow/ScanQrCodeFragment.kt | 1 +
.../SenderManualConnectionFragment.kt | 86 ++++++++-----------
4 files changed, 64 insertions(+), 78 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 92e8f8712..fad8d7e65 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -70,7 +70,7 @@ class PeerToPeerViewModel @Inject constructor(
PeerEventManager.registrationRequests.collect { (registrationId, payload) ->
_incomingRequest.value = IncomingRegistration(registrationId, payload)
- if (!isManualConnection) {
+ if (!p2PState.isUsingManualConnection) {
// QR-mode: auto-accept immediately
PeerEventManager.confirmRegistration(registrationId, true)
_registrationSuccess.postValue(true)
@@ -147,6 +147,7 @@ class PeerToPeerViewModel @Inject constructor(
val result = FingerprintFetcher.fetch(ip, port.toInt())
result.onSuccess { hash ->
Timber.d("hash ***** $hash")
+ p2PState.hash = hash
_getHashSuccess.postValue(hash)
// Notify the server after fetching the hash
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 07b61e60b..c13de8e9e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -19,6 +19,7 @@ import javax.inject.Inject
class RecipientVerificationFragment :
BaseBindingFragment(ConnectManuallyVerificationBinding::inflate) {
+
private val viewModel: PeerToPeerViewModel by activityViewModels()
private var payload: PeerConnectionPayload? = null
@@ -27,58 +28,49 @@ class RecipientVerificationFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+
arguments?.getString("payload")?.let { payloadJson ->
payload = Gson().fromJson(payloadJson, PeerConnectionPayload::class.java)
}
+
initListeners()
initObservers()
}
- private fun initListeners() {
-
- binding.toolbar.backClickListener = {
- peerServerStarterManager.stopServer()
- navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
- }
-
- binding.discardBtn.setOnClickListener {
- peerServerStarterManager.stopServer()
- navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
- }
+ private fun initListeners() = with(binding) {
+ toolbar.backClickListener = { navigateBackAndStopServer() }
+ discardBtn.setOnClickListener { navigateBackAndStopServer() }
- binding.confirmAndConnectBtn.setOnClickListener(null)
+ // Button is disabled until a request is received.
+ confirmAndConnectBtn.setOnClickListener(null)
}
- private fun initObservers() {
- binding.hashContentTextView.text = viewModel.p2PState.hash.formatHash()
-
+ private fun initObservers() = with(binding) {
+ hashContentTextView.text = viewModel.p2PState.hash.formatHash()
viewModel.p2PState.isUsingManualConnection = true
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.incomingRequest.collect { request ->
if (request != null) {
- binding.confirmAndConnectBtn.isEnabled = true
- binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
-
- // Set the click listener when the request is available
- binding.confirmAndConnectBtn.setOnClickListener {
+ confirmAndConnectBtn.isEnabled = true
+ confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange_btn)
+ confirmAndConnectBtn.setOnClickListener {
viewModel.onUserConfirmedRegistration(request.registrationId)
}
-
- binding.discardBtn.setOnClickListener {
- peerServerStarterManager.stopServer()
- navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ discardBtn.setOnClickListener {
viewModel.onUserRejectedRegistration(request.registrationId)
+ navigateBackAndStopServer()
}
} else {
- binding.confirmAndConnectBtn.isEnabled = false
- binding.confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange16_btn)
- binding.confirmAndConnectBtn.setOnClickListener(null) // Optional: clear listener
+ confirmAndConnectBtn.isEnabled = false
+ confirmAndConnectBtn.setBackgroundResource(R.drawable.bg_round_orange16_btn)
+ confirmAndConnectBtn.setOnClickListener(null)
}
}
}
}
+
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
navManager().navigateFromRecipientVerificationScreenToWaitingReceiverFragment()
@@ -86,4 +78,8 @@ class RecipientVerificationFragment :
}
}
-}
\ No newline at end of file
+ private fun navigateBackAndStopServer() {
+ peerServerStarterManager.stopServer()
+ navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 7626a6864..ec29dd40d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -64,6 +64,7 @@ class ScanQrCodeFragment :
viewModel.p2PState.port = payload.port.toString()
viewModel.p2PState.hash = payload.certificateHash
viewModel.p2PState.ip = payload.ipAddress
+
viewModel.startRegistration(
ip = payload.ipAddress,
port = payload.port.toString(),
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index e9bbbe3a5..f7663304d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -10,7 +10,7 @@ import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
import org.hzontal.shared_ui.bottomsheet.KeyboardUtil
-//TODO SHOW ERRORS IN THE BOTTOM
+// TODO: Show errors in the bottom sheet
class SenderManualConnectionFragment :
BaseBindingFragment(SenderManualConnectionBinding::inflate) {
@@ -18,63 +18,36 @@ class SenderManualConnectionFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
-
- initListeners()
initView()
+ initListeners()
+ initObservers()
}
- private fun initView() {
- binding.ipAddress.onChange {
- updateNextButtonState()
- }
- binding.pin.onChange {
- updateNextButtonState()
- }
-
- binding.port.onChange {
- updateNextButtonState()
- }
-
- initObservers()
+ private fun initView() = with(binding) {
+ ipAddress.onChange { updateNextButtonState() }
+ pin.onChange { updateNextButtonState() }
+ port.onChange { updateNextButtonState() }
updateNextButtonState()
-
- KeyboardUtil(binding.root)
-
+ KeyboardUtil(root)
}
- private fun initListeners() {
- binding.backBtn.setOnClickListener {
- nav().popBackStack()
- }
-
- binding.nextBtn.setOnClickListener {
+ private fun initListeners() = with(binding) {
+ backBtn.setOnClickListener { nav().popBackStack() }
+ toolbar.backClickListener = { nav().popBackStack() }
- }
- }
+ nextBtn.setOnClickListener {
+ val ip = ipAddress.text.toString()
+ val port = port.text.toString()
+ val pin = this.pin.text.toString()
- private fun isInputValid(): Boolean {
- return binding.ipAddress.text?.isNotBlank() == true &&
- binding.pin.text?.isNotBlank() == true
- }
+ viewModel.p2PState.apply {
+ this.ip = ip
+ this.port = port
+ this.pin = pin
+ }
- private fun updateNextButtonState() {
- val enabled = isInputValid()
- binding.nextBtn.isEnabled = enabled
- binding.nextBtn.setTextColor(
- ContextCompat.getColor(
- baseActivity,
- if (enabled) android.R.color.white else android.R.color.darker_gray
- )
- )
- binding.toolbar.backClickListener = { nav().popBackStack() }
- binding.backBtn.setOnClickListener { nav().popBackStack() }
- binding.nextBtn.setOnClickListener {
- viewModel.handleCertificate(
- ip = binding.ipAddress.text.toString(),
- port = binding.port.text.toString(),
- pin = binding.pin.text.toString()
- )
+ viewModel.handleCertificate(ip, port, pin)
}
}
@@ -89,4 +62,19 @@ class SenderManualConnectionFragment :
}
}
-}
\ No newline at end of file
+ private fun isInputValid(): Boolean = with(binding) {
+ ipAddress.text?.isNotBlank() == true &&
+ pin.text?.isNotBlank() == true
+ }
+
+ private fun updateNextButtonState() = with(binding) {
+ val enabled = isInputValid()
+ nextBtn.isEnabled = enabled
+ nextBtn.setTextColor(
+ ContextCompat.getColor(
+ baseActivity,
+ if (enabled) android.R.color.white else android.R.color.darker_gray
+ )
+ )
+ }
+}
From 3d96b7b9d08cdb0c6d8201805043c0ec776412af Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Fri, 11 Jul 2025 20:30:10 +0100
Subject: [PATCH 065/153] WIP send files flow
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 3 +-
.../data/peertopeer/model/P2PSession.kt | 10 ++----
.../data/peertopeer/model/P2PSharedState.kt | 2 +-
.../data/peertopeer/model/ProgressFile.kt | 2 ++
.../fragment/peertopeer/di/PeerModule.kt | 13 +++++--
.../senderflow/PrepareUploadFragment.kt | 34 ++++++++++++++-----
.../senderflow/WaitingSenderFragment.kt | 11 ++++--
7 files changed, 52 insertions(+), 23 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 60f92cf22..ef2b4b67e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -21,8 +21,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
-import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
@@ -171,7 +171,6 @@ class TellaPeerToPeerServer(
p2PSharedState.sessionId = sessionId
val session = P2PSession(title = request.title)
-
val responseFiles = request.files.map { file ->
val transmissionId = UUID.randomUUID().toString()
val receivingFile = ProgressFile(
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
index cbc81b86d..3208c63df 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
@@ -1,13 +1,7 @@
package org.horizontal.tella.mobile.data.peertopeer.model
-class P2PSession(
+data class P2PSession(
var status: SessionStatus = SessionStatus.WAITING,
var files: MutableMap = mutableMapOf(),
var title: String? = null
-) {
- val isActive: Boolean
- get() = status == SessionStatus.WAITING || status == SessionStatus.SENDING
-
- val hasFiles: Boolean
- get() = files.isNotEmpty()
-}
\ No newline at end of file
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
index dca849d6b..05d3a318a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
@@ -9,7 +9,7 @@ class P2PSharedState(
var pin: String? = null,
var session: P2PSession? = null,
var failedAttempts: Int = 0,
- var isUsingManualConnection: Boolean = false
+ var isUsingManualConnection: Boolean = false,
) {
fun clear() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt
index 760eff5a9..6c6a83f67 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/ProgressFile.kt
@@ -1,9 +1,11 @@
package org.horizontal.tella.mobile.data.peertopeer.model
+import com.hzontal.tella_vault.VaultFile
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
data class ProgressFile(
var file: P2PFile,
+ var vaultFile : VaultFile? = null,
var status: P2PFileStatus = P2PFileStatus.QUEUE,
var transmissionId: String? = null,
var path: String? = null,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
index b2c19475e..8e78991c6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/di/PeerModule.kt
@@ -6,6 +6,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import javax.inject.Singleton
@@ -27,7 +28,15 @@ object PeerModule {
@Provides
@Singleton
- fun provideP2PServerState(): P2PSharedState {
- return P2PSharedState()
+ fun provideSession(): P2PSession {
+ return P2PSession()
+ }
+
+ @Provides
+ @Singleton
+ fun provideP2PServerState(p2PSession: P2PSession): P2PSharedState {
+ val p2PSharedState = P2PSharedState()
+ p2PSharedState.session = p2PSession
+ return p2PSharedState
}
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 279b28307..78c07fd9d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -18,8 +18,12 @@ import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.bus.EventObserver
import org.horizontal.tella.mobile.bus.event.AudioRecordEvent
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
+import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
import org.horizontal.tella.mobile.databinding.FragmentPrepareUploadBinding
import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance
+import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.C
import org.horizontal.tella.mobile.views.activity.camera.CameraActivity
@@ -252,16 +256,29 @@ class PrepareUploadFragment :
binding.sendReportBtn.setOnClickListener {
if (isSubmitEnabled) {
val selectedFiles = filesRecyclerViewAdapter.getFiles()
+
if (selectedFiles.isNotEmpty()) {
- // Fill the PeerToPeerInstance in the ViewModel
- /* viewModel.peerToPeerInstance = PeerToPeerInstance(
- updated = System.currentTimeMillis(),
- widgetMediaFiles = viewModel.vaultFilesToMediaFiles(selectedFiles),
- title = binding.reportTitleEt.text.toString()
- )*/
+ val session = viewModel.p2PSharedState.session ?: P2PSession().also {
+ viewModel.p2PSharedState.session = it
+ }
- // Optional: add to bundle if still needed elsewhere
- bundle.putSerializable("selectedFiles", ArrayList(selectedFiles))
+ selectedFiles.forEach { vaultFile ->
+ val p2pFile = P2PFile(
+ id = vaultFile.id,
+ fileName = vaultFile.name,
+ size = vaultFile.size,
+ fileType = vaultFile.mimeType ?: "application/octet-stream",
+ sha256 = vaultFile.hash
+ )
+
+ val progressFile = ProgressFile(
+ file = p2pFile,
+ vaultFile = vaultFile,
+ status = P2PFileStatus.QUEUE
+ )
+
+ session.files[vaultFile.id] = progressFile
+ }
// Navigate
navManager().navigateFromPrepareUploadFragmentToWaitingSenderFragment()
@@ -275,6 +292,7 @@ class PrepareUploadFragment :
}
+
private fun showSubmitReportErrorSnackBar() {
val errorRes = R.string.Snackbar_Submit_Files_Error
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
index a29057b6a..0aeddb0cd 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
@@ -6,6 +6,7 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.hzontal.tella_vault.VaultFile
import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
@@ -39,9 +40,15 @@ class WaitingSenderFragment :
}
}
-
viewModel.prepareResults.observe(viewLifecycleOwner) { response ->
- navManager().navigateFromWaitingSenderFragmentToUploadFilesFragment()
+ val fileInfos = response.files
+ fileInfos.forEach { fileInfo ->
+ viewModel.p2PSharedState.session?.files?.let { filesMap ->
+ filesMap[fileInfo.id]?.transmissionId = fileInfo.transmissionId
+ }
+ navManager().navigateFromWaitingSenderFragmentToUploadFilesFragment()
+ }
}
+
}
}
\ No newline at end of file
From 0c76a8c1ff9b9f27cdccf4cb5cffaee82ac2effb Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Sun, 13 Jul 2025 10:30:43 +0100
Subject: [PATCH 066/153] Fix prepare upload flow and response
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 4 ++--
.../data/peertopeer/TellaPeerToPeerServer.kt | 12 ++++++----
.../data/peertopeer/model/P2PSharedState.kt | 2 +-
.../peertopeer/PeerPrepareUploadResponse.kt | 2 +-
.../fragment/peertopeer/SenderViewModel.kt | 23 +++++++++++--------
.../senderflow/PrepareUploadFragment.kt | 2 +-
.../senderflow/WaitingSenderFragment.kt | 5 ++--
7 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 92ae3c4a9..aba259002 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -84,7 +84,7 @@ class TellaPeerToPeerClient @Inject constructor(){
return@withContext try {
client.newCall(request).execute().use { response ->
- val body = response.body.string().orEmpty()
+ val body = response.body.string()
if (response.isSuccessful) {
return@use parseSessionIdFromResponse(body)
@@ -159,7 +159,7 @@ class TellaPeerToPeerClient @Inject constructor(){
.build()
client.newCall(request).execute().use { response ->
- val responseBody = response.body?.string().orEmpty()
+ val responseBody = response.body.string()
return@withContext if (response.isSuccessful) {
parseTransmissionId(responseBody)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index ef2b4b67e..603e2a86e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -19,6 +19,8 @@ import io.ktor.server.routing.routing
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
@@ -92,7 +94,7 @@ class TellaPeerToPeerServer(
CoroutineScope(Dispatchers.IO).launch {
peerToPeerManager.notifyClientConnected(p2PSharedState.hash)
}
- call.respondText("pong", status = HttpStatusCode.OK)
+ call.respondText("ping", status = HttpStatusCode.OK)
}
post(PeerApiRoutes.REGISTER) {
@@ -187,10 +189,10 @@ class TellaPeerToPeerServer(
p2PSharedState.session = session
- call.respond(
- HttpStatusCode.OK,
- PeerPrepareUploadResponse(files = responseFiles)
- )
+ val responsePayload = PeerPrepareUploadResponse(files = responseFiles)
+ val json = Json.encodeToString(value = responsePayload)
+ println("✅ JSON to send: $json") // or Timber.d
+ call.respond(HttpStatusCode.OK, responsePayload)
} else {
call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
index 05d3a318a..d634c90ad 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
@@ -8,7 +8,7 @@ class P2PSharedState(
var hash: String = "",
var pin: String? = null,
var session: P2PSession? = null,
- var failedAttempts: Int = 0,
+ private var failedAttempts: Int = 0,
var isUsingManualConnection: Boolean = false,
) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
index 6ebf9d860..549628dd8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerPrepareUploadResponse.kt
@@ -7,7 +7,7 @@ data class FileInfo(
val id: String,
val transmissionId: String
)
-
+@Serializable
data class PeerPrepareUploadResponse(
val files: List
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
index 197f4ff86..9fe1cf73b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
@@ -77,18 +77,15 @@ class SenderViewModel @Inject constructor(
return vaultFiles
}
- fun prepareUploadsFromVaultFiles(
- files: List,
- title: String = "Title of the report"
- ) {
+ fun prepareUploadsFromVaultFiles() {
viewModelScope.launch {
when (val result = peerClient.prepareUpload(
ip = p2PSharedState.ip,
port = p2PSharedState.port,
expectedFingerprint = p2PSharedState.hash,
- title = title,
- files = files,
+ title = getTitleFromState(),
+ files = getVaultFilesFromState(),
sessionId = p2PSharedState.sessionId
)) {
is PrepareUploadResult.Success -> {
@@ -102,9 +99,6 @@ class SenderViewModel @Inject constructor(
}
_prepareResults.postValue(PeerPrepareUploadResponse(result.transmissions))
-
- //TODO UNIFY THE INSTANCE EITHER USE PEERTOPEERINSTANCE OR USE PEERSESSIONMANAGER
- //TODO UNIFY THE FORMENDVIEW TO USE THE NEW STATE MANAGER ...
}
is PrepareUploadResult.Forbidden -> {
@@ -133,6 +127,17 @@ class SenderViewModel @Inject constructor(
}
}
+ private fun getVaultFilesFromState(): List {
+ return p2PSharedState.session?.files
+ ?.values
+ ?.mapNotNull { it.vaultFile }
+ .orEmpty()
+ }
+
+ private fun getTitleFromState(): String {
+ return p2PSharedState.session?.title ?: ""
+ }
+
override fun onCleared() {
super.onCleared()
p2PSharedState.clear()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 78c07fd9d..5deed43ad 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -256,6 +256,7 @@ class PrepareUploadFragment :
binding.sendReportBtn.setOnClickListener {
if (isSubmitEnabled) {
val selectedFiles = filesRecyclerViewAdapter.getFiles()
+ viewModel.p2PSharedState.session?.title = binding.reportTitleEt.text.toString()
if (selectedFiles.isNotEmpty()) {
val session = viewModel.p2PSharedState.session ?: P2PSession().also {
@@ -292,7 +293,6 @@ class PrepareUploadFragment :
}
-
private fun showSubmitReportErrorSnackBar() {
val errorRes = R.string.Snackbar_Submit_Files_Error
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
index 0aeddb0cd..db6e1a9b5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
@@ -22,9 +22,8 @@ class WaitingSenderFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.toolbar.setStartTextTitle(getString(R.string.send_files))
binding.waitingText.text = getString(R.string.waiting_for_the_recipient_to_accept_files)
- val selectedFiles =
- arguments?.getSerializable("selectedFiles") as? List ?: emptyList()
- viewModel.prepareUploadsFromVaultFiles(selectedFiles)
+
+ viewModel.prepareUploadsFromVaultFiles()
binding.toolbar.backClickListener = {
navManager().navigateBackToStartNearBySharingFragmentAndClearBackStack()
}
From 1bc76e2e555dcc3eaa1243e3bbfb46522f4a9c26 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Sun, 13 Jul 2025 13:24:57 +0100
Subject: [PATCH 067/153] prepare files for sender/receiver ui from the state
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 40 +++++++++--------
.../data/peertopeer/model/P2PSession.kt | 1 +
.../data/peertopeer/model/P2PSharedState.kt | 3 --
.../domain/peertopeer/PeerEventManager.kt | 4 --
.../tella/mobile/util/NavigationManager.kt | 4 ++
...rViewModel.kt => FileTransferViewModel.kt} | 13 +++++-
.../peertopeer/PeerToPeerViewModel.kt | 30 ++++++++++++-
.../receipentflow/RecipientSuccessFragment.kt | 26 ++++-------
.../RecipientUploadFilesFragment.kt | 43 +++++++++++++++++++
.../receipentflow/WaitingReceiverFragment.kt | 5 ---
...agment.kt => SenderUploadFilesFragment.kt} | 4 +-
.../res/navigation/peer_to_peer_graph.xml | 38 ++++++++++------
12 files changed, 142 insertions(+), 69 deletions(-)
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/{SenderViewModel.kt => FileTransferViewModel.kt} (92%)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/{UploadFilesFragment.kt => SenderUploadFilesFragment.kt} (94%)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 603e2a86e..a283a8191 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -165,39 +165,41 @@ class TellaPeerToPeerServer(
}
val accepted = PeerEventManager.emitPrepareUploadRequest(request)
+
if (accepted) {
- val sessionId = serverSession?.sessionId ?: run {
+ val session = p2PSharedState.session ?: run {
call.respond(HttpStatusCode.InternalServerError, "Missing session")
return@post
}
- p2PSharedState.sessionId = sessionId
- val session = P2PSession(title = request.title)
+ // Assign a transmissionId to each matching file
val responseFiles = request.files.map { file ->
val transmissionId = UUID.randomUUID().toString()
- val receivingFile = ProgressFile(
- file = file,
- transmissionId = transmissionId
- )
- session.files[transmissionId] = receivingFile
-
- FileInfo(
- id = file.id,
- transmissionId = transmissionId
- )
- }
- p2PSharedState.session = session
+ val progressFile =
+ session.files.values.find { it.file.id == file.id }
+
+ if (progressFile != null) {
+ progressFile.transmissionId = transmissionId
+ } else {
+ // Fallback, in case something went wrong with pre-population
+ session.files[transmissionId] =
+ ProgressFile(file = file, transmissionId = transmissionId)
+ }
+
+ FileInfo(id = file.id, transmissionId = transmissionId)
+ }
- val responsePayload = PeerPrepareUploadResponse(files = responseFiles)
- val json = Json.encodeToString(value = responsePayload)
- println("✅ JSON to send: $json") // or Timber.d
- call.respond(HttpStatusCode.OK, responsePayload)
+ call.respond(
+ HttpStatusCode.OK,
+ PeerPrepareUploadResponse(files = responseFiles)
+ )
} else {
call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
}
}
+
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
index 3208c63df..c14abecd6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSession.kt
@@ -1,6 +1,7 @@
package org.horizontal.tella.mobile.data.peertopeer.model
data class P2PSession(
+ var sessionId: String = "",
var status: SessionStatus = SessionStatus.WAITING,
var files: MutableMap = mutableMapOf(),
var title: String? = null
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
index d634c90ad..8a5052127 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PSharedState.kt
@@ -3,8 +3,6 @@ package org.horizontal.tella.mobile.data.peertopeer.model
class P2PSharedState(
var ip: String = "",
var port: String = "",
- var sessionId: String = "",
- //THE HASH IS THE SAME EXPECTED FINGER PRINT
var hash: String = "",
var pin: String? = null,
var session: P2PSession? = null,
@@ -15,7 +13,6 @@ class P2PSharedState(
fun clear() {
ip = ""
port = ""
- sessionId = ""
hash = ""
pin = null
session = null
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
index 4f24426a5..632a21f3c 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
@@ -17,16 +17,12 @@ object PeerEventManager {
private val registrationDecisionMap = mutableMapOf>()
-
-
// Call this when registration succeeds
suspend fun emitRegistrationSuccess() {
registrationEvents.emit(true)
}
// we can add emitRegistrationFailure or other event types if needed
-
-
private val _prepareUploadEvents = MutableSharedFlow(replay = 1)
val prepareUploadEvents = _prepareUploadEvents.asSharedFlow()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index dc5d9cd3f..ddb249c4e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -224,6 +224,10 @@ class NavigationManager(
fun navigateFromWaitingSenderFragmentToUploadFilesFragment() {
navigateToWithBundle(R.id.action_waitingSenderFragment_to_uploadFilesFragment)
+ }
+
+ fun navigateFromRecipientSuccessFragmentToRecipientUploadFilesFragment() {
+ navigateToWithBundle(R.id.action_recipientSuccessFragment_to_recipientUploadFilesFragment)
}
fun navigateBackToStartNearBySharingFragmentAndClearBackStack() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
similarity index 92%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
index 9fe1cf73b..b6e27c278 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/SenderViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
@@ -19,6 +19,7 @@ import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance
+import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.util.Event
import org.horizontal.tella.mobile.util.fromJsonToObjectList
@@ -86,10 +87,10 @@ class SenderViewModel @Inject constructor(
expectedFingerprint = p2PSharedState.hash,
title = getTitleFromState(),
files = getVaultFilesFromState(),
- sessionId = p2PSharedState.sessionId
+ sessionId = getSessionId()
)) {
is PrepareUploadResult.Success -> {
- peerToPeerInstance?.sessionID = p2PSharedState.sessionId
+ peerToPeerInstance?.sessionID = getSessionId()
val fileInfoMap = result.transmissions.associateBy { it.id }
peerToPeerInstance?.widgetMediaFiles?.forEach { mediaFile ->
@@ -138,11 +139,19 @@ class SenderViewModel @Inject constructor(
return p2PSharedState.session?.title ?: ""
}
+ private fun getSessionId(): String {
+ return p2PSharedState.session?.sessionId ?: ""
+ }
+
override fun onCleared() {
super.onCleared()
p2PSharedState.clear()
}
+ fun confirmPrepareUpload(sessionId: String, accepted: Boolean) {
+ PeerEventManager.resolveUserDecision(sessionId, accepted)
+ }
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index fad8d7e65..3d805e6a4 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -17,6 +17,7 @@ import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
+import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
@@ -24,6 +25,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
import timber.log.Timber
+import java.util.UUID
import javax.inject.Inject
@HiltViewModel
@@ -56,6 +58,9 @@ class PeerToPeerViewModel @Inject constructor(
init {
viewModelScope.launch {
PeerEventManager.prepareUploadEvents.collect { request ->
+ p2PState.session?.sessionId = request.sessionId
+ p2PState.session?.title = request.title
+ populateFilesFromRequest(request, p2PState)
_incomingPrepareRequest.postValue(request)
}
}
@@ -103,7 +108,7 @@ class PeerToPeerViewModel @Inject constructor(
when (val result = peerClient.registerPeerDevice(ip, port, hash, pin)) {
is RegisterPeerResult.Success -> {
with(p2PState) {
- this.sessionId = result.sessionId
+ this.session?.sessionId = result.sessionId
}
_registrationSuccess.postValue(true)
@@ -172,7 +177,6 @@ class PeerToPeerViewModel @Inject constructor(
}
fun onUserRejectedRegistration(registrationId: String) {
- //TODO when the user reject i THINK the client should go back to the
PeerEventManager.confirmRegistration(registrationId, accepted = false)
}
@@ -182,6 +186,28 @@ class PeerToPeerViewModel @Inject constructor(
}
+ fun getSessionId(): String {
+ return p2PState.session?.sessionId ?: ""
+ }
+
+ fun populateFilesFromRequest(request: PrepareUploadRequest, sharedState: P2PSharedState) {
+ val session = sharedState.session ?: return
+
+ session.sessionId = request.sessionId
+ session.title = request.title
+
+ request.files.forEach { p2pFile ->
+ val transmissionId = UUID.randomUUID().toString()
+
+ val progressFile = ProgressFile(
+ file = p2pFile,
+ transmissionId = transmissionId
+ )
+
+ session.files[transmissionId] = progressFile
+ }
+ }
+
override fun onCleared() {
super.onCleared()
p2PState.clear()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 540b268f4..009a86e7d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -8,44 +8,34 @@ import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
-import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
*/
-class RecipientSuccessFragment : BaseBindingFragment(FragmentRecipientSuccessBinding::inflate){
+class RecipientSuccessFragment :
+ BaseBindingFragment(FragmentRecipientSuccessBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- }
-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
initView()
}
+
private fun initView() {
- val fileCount = arguments?.getInt("fileCount") ?: 0
- val sessionId = arguments?.getString("sessionId").orEmpty()
with(binding) {
// Set the dynamic message
- waitingText.text = getString(R.string.prepare_upload_message, fileCount)
+ waitingText.text =
+ getString(R.string.prepare_upload_message, viewModel.p2PState.session?.files?.size)
// Handle Accept/Reject buttons
acceptBtn.setOnClickListener {
- // onAcceptFilesSelected()
- viewModel.confirmPrepareUpload(sessionId, true)
- DialogUtils.showBottomMessage(
- baseActivity,
- "The receiver accepted the files transfer ",
- false,
- 3000
- )
+ viewModel.confirmPrepareUpload(viewModel.getSessionId(), true)
+ navManager().navigateFromRecipientSuccessFragmentToRecipientUploadFilesFragment()
}
rejectBtn.setOnClickListener {
//TODO WE MOVE THIS TO THE NAV MANAGER
- viewModel.confirmPrepareUpload(sessionId, false)
+ viewModel.confirmPrepareUpload(viewModel.getSessionId(), false)
// Set result safely via SavedStateHandle
findNavController().previousBackStackEntry
?.savedStateHandle
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
new file mode 100644
index 000000000..1c1e8b02a
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -0,0 +1,43 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.activityViewModels
+import org.horizontal.tella.mobile.MyApplication
+import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
+import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
+
+class RecipientUploadFilesFragment:
+ BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
+
+ private val viewModel: SenderViewModel by activityViewModels()
+ private lateinit var endView: PeerToPeerEndView
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ showFormEndView()
+ }
+
+ private fun showFormEndView() {
+ if (viewModel.peerToPeerInstance == null) {
+ return
+ }
+
+ viewModel.peerToPeerInstance?.let { peerInstance ->
+
+ endView = PeerToPeerEndView(
+ baseActivity,
+ peerInstance.title,
+ )
+ endView.setInstance(
+ peerInstance, MyApplication.isConnectedToInternet(baseActivity), false
+ )
+ binding.endViewContainer.removeAllViews()
+ binding.endViewContainer.addView(endView)
+ endView.clearPartsProgress(peerInstance)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
index 990714528..f56629d49 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
@@ -40,11 +40,6 @@ class WaitingReceiverFragment :
viewModel.incomingPrepareRequest.observe(viewLifecycleOwner) { request ->
if (request != null && !viewModel.hasNavigatedToSuccessFragment) {
viewModel.hasNavigatedToSuccessFragment = true
-
- val fileCount = request.files.size
- bundle.putInt("fileCount", fileCount)
- bundle.putString("sessionId", request.sessionId)
-
navManager().navigateFromWaitingReceiverFragmentToRecipientSuccessFragment()
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
similarity index 94%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index 92b3bcb7e..4fffd1847 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/UploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -9,11 +9,11 @@ import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
-class UploadFilesFragment :
+class SenderUploadFilesFragment :
BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
private val viewModel: SenderViewModel by activityViewModels()
- protected lateinit var endView: PeerToPeerEndView
+ private lateinit var endView: PeerToPeerEndView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 939dae8ca..435a7c09c 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -35,7 +35,7 @@
android:id="@+id/connectManuallyVerificationFragment"
android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow.SenderVerificationFragment"
android:label="ConnectManuallyVerificationScreen"
- tools:layout="@layout/connect_manually_verification" >
+ tools:layout="@layout/connect_manually_verification">
@@ -71,7 +71,7 @@
android:id="@+id/deviceInfoScreen"
android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow.ShowDeviceInfoFragment"
android:label="DeviceInfoScreen"
- tools:layout="@layout/show_device_info_layout" >
+ tools:layout="@layout/show_device_info_layout">
@@ -88,11 +88,17 @@
app:destination="@id/waitingReceiverFragment" />
+
+
+ tools:layout="@layout/fragment_prepare_upload">
@@ -110,8 +116,8 @@
+ android:label="WaitingReceiverFragment"
+ tools:layout="@layout/fragment_waiting">
@@ -119,18 +125,22 @@
+ android:label="SuccessConnectFragment"
+ tools:layout="@layout/fragment_success_connect_flow" />
+ android:label="RecipientSuccessFragment"
+ tools:layout="@layout/fragment_recipient_success">
+
+
+ android:label="WaitingSenderFragment"
+ tools:layout="@layout/fragment_waiting">
@@ -138,8 +148,8 @@
+ android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow.SenderVerificationFragment"
+ android:label="UploadFilesFragment"
+ tools:layout="@layout/fragment_upload_files" />
\ No newline at end of file
From 2d84572ebd08a1b909f5d06a7d37bb06dc4a057c Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Sun, 13 Jul 2025 15:45:58 +0100
Subject: [PATCH 068/153] Prepare data to send files
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 39 ++++++++-----------
.../peertopeer/FileTransferViewModel.kt | 3 +-
.../peertopeer/PeerToPeerViewModel.kt | 16 ++++----
.../receipentflow/RecipientSuccessFragment.kt | 20 ++++++----
.../RecipientUploadFilesFragment.kt | 4 +-
.../receipentflow/WaitingReceiverFragment.kt | 5 +++
.../senderflow/PrepareUploadFragment.kt | 6 +--
.../senderflow/SenderUploadFilesFragment.kt | 4 +-
.../senderflow/WaitingSenderFragment.kt | 7 +---
.../res/navigation/peer_to_peer_graph.xml | 2 +-
10 files changed, 52 insertions(+), 54 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index a283a8191..4d9fd7002 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -165,41 +165,36 @@ class TellaPeerToPeerServer(
}
val accepted = PeerEventManager.emitPrepareUploadRequest(request)
-
if (accepted) {
- val session = p2PSharedState.session ?: run {
+ val sessionId = serverSession?.sessionId ?: run {
call.respond(HttpStatusCode.InternalServerError, "Missing session")
return@post
}
+ p2PSharedState.session?.sessionId = sessionId
+ val session = P2PSession(title = request.title)
- // Assign a transmissionId to each matching file
val responseFiles = request.files.map { file ->
val transmissionId = UUID.randomUUID().toString()
-
- val progressFile =
- session.files.values.find { it.file.id == file.id }
-
- if (progressFile != null) {
- progressFile.transmissionId = transmissionId
- } else {
- // Fallback, in case something went wrong with pre-population
- session.files[transmissionId] =
- ProgressFile(file = file, transmissionId = transmissionId)
- }
-
- FileInfo(id = file.id, transmissionId = transmissionId)
+ val receivingFile = ProgressFile(
+ file = file,
+ transmissionId = transmissionId
+ )
+ session.files[transmissionId] = receivingFile
+
+ FileInfo(
+ id = file.id,
+ transmissionId = transmissionId
+ )
}
- call.respond(
- HttpStatusCode.OK,
- PeerPrepareUploadResponse(files = responseFiles)
- )
+ p2PSharedState.session = session
+
+ val responsePayload = PeerPrepareUploadResponse(files = responseFiles)
+ call.respond(HttpStatusCode.OK, responsePayload)
} else {
call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
}
}
-
-
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
index b6e27c278..fd855f5fc 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
@@ -28,7 +28,7 @@ import javax.inject.Inject
@HiltViewModel
-class SenderViewModel @Inject constructor(
+class FileTransferViewModel @Inject constructor(
private val peerClient: TellaPeerToPeerClient,
var p2PSharedState: P2PSharedState
) : ViewModel() {
@@ -90,7 +90,6 @@ class SenderViewModel @Inject constructor(
sessionId = getSessionId()
)) {
is PrepareUploadResult.Success -> {
- peerToPeerInstance?.sessionID = getSessionId()
val fileInfoMap = result.transmissions.associateBy { it.id }
peerToPeerInstance?.widgetMediaFiles?.forEach { mediaFile ->
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 3d805e6a4..7394d0cd0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -12,6 +12,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
+import org.horizontal.tella.mobile.bus.SingleLiveEvent
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
@@ -39,17 +40,17 @@ class PeerToPeerViewModel @Inject constructor(
var isManualConnection: Boolean = true // default is manual
var hasNavigatedToSuccessFragment = false
var currentNetworkInfo: NetworkInfo? = null
- private val _registrationSuccess = MutableLiveData()
+ private val _registrationSuccess = SingleLiveEvent()
val registrationSuccess: LiveData get() = _registrationSuccess
- private val _getHashSuccess = MutableLiveData()
+ private val _getHashSuccess = SingleLiveEvent()
val getHashSuccess: LiveData get() = _getHashSuccess
- private val _getHashError = MutableLiveData()
+ private val _getHashError = SingleLiveEvent()
val getHashError: LiveData get() = _getHashError
val clientHash = peerToPeerManager.clientConnected
- private val _registrationServerSuccess = MutableLiveData()
+ private val _registrationServerSuccess = SingleLiveEvent()
val registrationServerSuccess: LiveData = _registrationServerSuccess
- private val _incomingPrepareRequest = MutableLiveData()
- val incomingPrepareRequest: MutableLiveData = _incomingPrepareRequest
+ private val _incomingPrepareRequest = SingleLiveEvent()
+ val incomingPrepareRequest: SingleLiveEvent = _incomingPrepareRequest
private val _incomingRequest = MutableStateFlow(null)
val incomingRequest: StateFlow = _incomingRequest
private val networkInfoManager = NetworkInfoManager(context)
@@ -58,9 +59,6 @@ class PeerToPeerViewModel @Inject constructor(
init {
viewModelScope.launch {
PeerEventManager.prepareUploadEvents.collect { request ->
- p2PState.session?.sessionId = request.sessionId
- p2PState.session?.title = request.title
- populateFilesFromRequest(request, p2PState)
_incomingPrepareRequest.postValue(request)
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 009a86e7d..935e2215b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -8,34 +8,40 @@ import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.hzontal.shared_ui.utils.DialogUtils
/**
* Created by wafa on 3/6/2025.
*/
-class RecipientSuccessFragment :
- BaseBindingFragment(FragmentRecipientSuccessBinding::inflate) {
+class RecipientSuccessFragment : BaseBindingFragment(FragmentRecipientSuccessBinding::inflate){
private val viewModel: PeerToPeerViewModel by activityViewModels()
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ }
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
initView()
}
-
private fun initView() {
+ val fileCount = arguments?.getInt("fileCount") ?: 0
+ val sessionId = arguments?.getString("sessionId").orEmpty()
with(binding) {
// Set the dynamic message
- waitingText.text =
- getString(R.string.prepare_upload_message, viewModel.p2PState.session?.files?.size)
+ waitingText.text = getString(R.string.prepare_upload_message, fileCount)
// Handle Accept/Reject buttons
acceptBtn.setOnClickListener {
- viewModel.confirmPrepareUpload(viewModel.getSessionId(), true)
+
+ viewModel.confirmPrepareUpload(sessionId, true)
+
navManager().navigateFromRecipientSuccessFragmentToRecipientUploadFilesFragment()
}
rejectBtn.setOnClickListener {
//TODO WE MOVE THIS TO THE NAV MANAGER
- viewModel.confirmPrepareUpload(viewModel.getSessionId(), false)
+ viewModel.confirmPrepareUpload(sessionId, false)
// Set result safely via SavedStateHandle
findNavController().previousBackStackEntry
?.savedStateHandle
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index 1c1e8b02a..c34356e72 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -6,13 +6,13 @@ import androidx.fragment.app.activityViewModels
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
class RecipientUploadFilesFragment:
BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
- private val viewModel: SenderViewModel by activityViewModels()
+ private val viewModel: FileTransferViewModel by activityViewModels()
private lateinit var endView: PeerToPeerEndView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
index f56629d49..990714528 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
@@ -40,6 +40,11 @@ class WaitingReceiverFragment :
viewModel.incomingPrepareRequest.observe(viewLifecycleOwner) { request ->
if (request != null && !viewModel.hasNavigatedToSuccessFragment) {
viewModel.hasNavigatedToSuccessFragment = true
+
+ val fileCount = request.files.size
+ bundle.putInt("fileCount", fileCount)
+ bundle.putString("sessionId", request.sessionId)
+
navManager().navigateFromWaitingReceiverFragmentToRecipientSuccessFragment()
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 5deed43ad..0ce5648b7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -6,7 +6,6 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.setFragmentResultListener
-import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.google.firebase.crashlytics.FirebaseCrashlytics
@@ -22,7 +21,6 @@ import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
import org.horizontal.tella.mobile.databinding.FragmentPrepareUploadBinding
-import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance
import org.horizontal.tella.mobile.domain.peertopeer.P2PFile
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.C
@@ -33,7 +31,7 @@ import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_AUDIO
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_VAULT_FILE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.OnNavBckListener
-import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.recorder.MicActivity
import org.horizontal.tella.mobile.views.fragment.recorder.REPORT_ENTRY
import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.AttachmentsActivitySelector
@@ -54,7 +52,7 @@ class PrepareUploadFragment :
IReportAttachmentsHandler, OnNavBckListener {
private lateinit var gridLayoutManager: GridLayoutManager
private var isTitleEnabled = false
- private val viewModel: SenderViewModel by activityViewModels()
+ private val viewModel: FileTransferViewModel by activityViewModels()
private var disposables =
MyApplication.bus().createCompositeDisposable()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index 4fffd1847..0e9ab95a6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -6,13 +6,13 @@ import androidx.fragment.app.activityViewModels
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
class SenderUploadFilesFragment :
BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
- private val viewModel: SenderViewModel by activityViewModels()
+ private val viewModel: FileTransferViewModel by activityViewModels()
private lateinit var endView: PeerToPeerEndView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
index db6e1a9b5..a4b801f05 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
@@ -4,20 +4,17 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
-import com.hzontal.tella_vault.VaultFile
import org.horizontal.tella.mobile.R
-import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.SenderViewModel
-import org.hzontal.shared_ui.utils.DialogUtils
+import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
/**
* Created by wafa on 3/6/2025.
*/
class WaitingSenderFragment :
BaseBindingFragment(FragmentWaitingBinding::inflate) {
- private val viewModel: SenderViewModel by activityViewModels()
+ private val viewModel: FileTransferViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.toolbar.setStartTextTitle(getString(R.string.send_files))
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 435a7c09c..75c5e882e 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -148,7 +148,7 @@
From f00b04470bfcc8f88db9a58eb62e7865aa15f1e1 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Sun, 13 Jul 2025 17:54:41 +0100
Subject: [PATCH 069/153] WIP client upload
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 43 +++
.../peertopeer/network/ProgressRequestBody.kt | 30 +++
.../data/peertopeer/remote/PeerApiRoutes.kt | 7 +
.../peertopeer/FileTransferViewModel.kt | 61 ++++-
.../peertopeer/PeerToPeerViewModel.kt | 23 --
.../senderflow/SenderUploadFilesFragment.kt | 35 +--
.../senderflow/SenderVerificationFragment.kt | 1 -
.../uwazi/widgets/PeerToPeerEndView.java | 250 ++++++------------
8 files changed, 240 insertions(+), 210 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/network/ProgressRequestBody.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index aba259002..57accb6b7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -12,6 +12,7 @@ import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_JSON
import org.horizontal.tella.mobile.data.peertopeer.PeerToPeerConstants.CONTENT_TYPE_OCTET
+import org.horizontal.tella.mobile.data.peertopeer.network.ProgressRequestBody
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
@@ -21,6 +22,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.json.JSONObject
import timber.log.Timber
+import java.io.InputStream
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
@@ -199,4 +201,45 @@ class TellaPeerToPeerClient @Inject constructor(){
}
+ suspend fun uploadFileWithProgress(
+ ip: String,
+ port: String,
+ expectedFingerprint: String,
+ sessionId: String,
+ fileId: String,
+ transmissionId: String,
+ inputStream: InputStream,
+ fileSize: Long,
+ onProgress: (bytesWritten: Long, totalBytes: Long) -> Unit
+ ): Boolean = withContext(Dispatchers.IO) {
+ val url = PeerApiRoutes.buildUploadUrl(ip, port, sessionId, fileId, transmissionId)
+
+ val client = getClientWithFingerprintValidation(expectedFingerprint)
+
+ val requestBody = ProgressRequestBody(inputStream, fileSize, onProgress)
+
+ val request = Request.Builder()
+ .url(url)
+ .post(requestBody)
+ .addHeader(CONTENT_TYPE, CONTENT_TYPE_OCTET)
+ .build()
+
+ return@withContext try {
+ client.newCall(request).execute().use { response ->
+ if (response.isSuccessful) {
+ Timber.d("Upload successful for $fileId")
+ true
+ } else {
+ Timber.e("Upload failed for $fileId with code ${response.code}")
+ false
+ }
+ }
+ } catch (e: Exception) {
+ Timber.e(e, "Exception while uploading $fileId")
+ false
+ }
+ }
+
+
+
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/network/ProgressRequestBody.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/network/ProgressRequestBody.kt
new file mode 100644
index 000000000..f2e53d5e0
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/network/ProgressRequestBody.kt
@@ -0,0 +1,30 @@
+package org.horizontal.tella.mobile.data.peertopeer.network
+
+import okhttp3.MediaType
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.RequestBody
+import okio.BufferedSink
+import java.io.InputStream
+
+class ProgressRequestBody(
+ private val inputStream: InputStream,
+ private val contentLength: Long,
+ private val onProgress: (Long, Long) -> Unit
+) : RequestBody() {
+
+ override fun contentType(): MediaType? = "application/octet-stream".toMediaTypeOrNull()
+
+ override fun contentLength(): Long = contentLength
+
+ override fun writeTo(sink: BufferedSink) {
+ val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
+ var uploaded = 0L
+ var read: Int
+
+ while (inputStream.read(buffer).also { read = it } != -1) {
+ sink.write(buffer, 0, read)
+ uploaded += read
+ onProgress(uploaded, contentLength)
+ }
+ }
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt
index 5f8ae716b..8af395c92 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/remote/PeerApiRoutes.kt
@@ -3,9 +3,16 @@ package org.horizontal.tella.mobile.data.peertopeer.remote
object PeerApiRoutes {
const val REGISTER = "/api/v1/register"
const val PREPARE_UPLOAD = "/api/v1/prepare-upload"
+ const val UPLOAD = "/api/v1/upload"
const val PING = "/api/v1/ping"
fun buildUrl(ip: String, port: String, endpoint: String): String {
return "https://$ip:$port$endpoint"
}
+
+ fun buildUploadUrl(ip: String, port: String, sessionId: String, fileId: String, transmissionId: String): String {
+ val baseUrl = buildUrl(ip, port, UPLOAD)
+ return "$baseUrl?sessionId=$sessionId&fileId=$fileId&transmissionId=$transmissionId"
+ }
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
index fd855f5fc..88ac3b764 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
@@ -14,13 +14,15 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
+import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance
-import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
+import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.Event
import org.horizontal.tella.mobile.util.fromJsonToObjectList
import timber.log.Timber
@@ -37,6 +39,8 @@ class FileTransferViewModel @Inject constructor(
private val _prepareRejected = MutableLiveData>()
val prepareRejected: LiveData> = _prepareRejected
var peerToPeerInstance: PeerToPeerInstance? = null
+ private val _uploadProgress = MutableLiveData() // value from 0 to 100
+ val uploadProgress: LiveData get() = _uploadProgress
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
@@ -127,6 +131,57 @@ class FileTransferViewModel @Inject constructor(
}
}
+
+ fun uploadAllFiles(onFileUploaded: () -> Unit) {
+ viewModelScope.launch {
+ val session = p2PSharedState.session ?: return@launch
+ val ip = p2PSharedState.ip
+ val port = p2PSharedState.port
+ val fingerprint = p2PSharedState.hash
+
+ val totalSize = session.files.values.sumOf { it.vaultFile?.size ?: 0L }
+
+ session.files.values.forEach { progressFile ->
+ val vaultFile = progressFile.vaultFile ?: return@forEach
+ val inputStream =MediaFileHandler.getStream(vaultFile) // Use your actual method here to get InputStream
+
+ progressFile.status = P2PFileStatus.SENDING
+
+ try {
+ if (inputStream != null) {
+ peerClient.uploadFileWithProgress(
+ ip = ip,
+ port = port,
+ expectedFingerprint = fingerprint,
+ sessionId = session.sessionId,
+ fileId = progressFile.file.id,
+ transmissionId = progressFile.transmissionId.orEmpty(),
+ inputStream = inputStream,
+ fileSize = vaultFile.size
+ ) { written, _ ->
+ progressFile.bytesTransferred = written.toInt()
+
+ val uploaded = session.files.values.sumOf { it.bytesTransferred }
+ val percent = if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
+ _uploadProgress.postValue(percent)
+ }
+ }
+
+ progressFile.status = P2PFileStatus.FINISHED
+ onFileUploaded()
+ } catch (e: Exception) {
+ progressFile.status = P2PFileStatus.FAILED
+ Timber.e(e, "Upload failed for file ${progressFile.file.fileName}")
+ } finally {
+ inputStream?.close()
+ }
+ }
+
+ session.status = SessionStatus.FINISHED
+ }
+ }
+
+
private fun getVaultFilesFromState(): List {
return p2PSharedState.session?.files
?.values
@@ -147,10 +202,6 @@ class FileTransferViewModel @Inject constructor(
p2PSharedState.clear()
}
- fun confirmPrepareUpload(sessionId: String, accepted: Boolean) {
- PeerEventManager.resolveUserDecision(sessionId, accepted)
- }
-
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
index 7394d0cd0..0779e73a8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
@@ -181,29 +181,6 @@ class PeerToPeerViewModel @Inject constructor(
fun clearPrepareRequest() {
_incomingPrepareRequest.value = null
hasNavigatedToSuccessFragment = false
-
- }
-
- fun getSessionId(): String {
- return p2PState.session?.sessionId ?: ""
- }
-
- fun populateFilesFromRequest(request: PrepareUploadRequest, sharedState: P2PSharedState) {
- val session = sharedState.session ?: return
-
- session.sessionId = request.sessionId
- session.title = request.title
-
- request.files.forEach { p2pFile ->
- val transmissionId = UUID.randomUUID().toString()
-
- val progressFile = ProgressFile(
- file = p2pFile,
- transmissionId = transmissionId
- )
-
- session.files[transmissionId] = progressFile
- }
}
override fun onCleared() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index 0e9ab95a6..585a088e2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -18,26 +18,27 @@ class SenderUploadFilesFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
showFormEndView()
+ observeUploadProgress()
}
private fun showFormEndView() {
- if (viewModel.peerToPeerInstance == null) {
- return
- }
-
- viewModel.peerToPeerInstance?.let { peerInstance ->
+ val session = viewModel.p2PSharedState.session ?: return
+ val files = session.files.values.toList()
+
+ endView = PeerToPeerEndView(
+ baseActivity, session.title ?: "Transfer"
+ )
+ endView.setFiles(files, MyApplication.isConnectedToInternet(baseActivity), false)
+ binding.endViewContainer.removeAllViews()
+ binding.endViewContainer.addView(endView)
+ endView.clearPartsProgress(files, session.status)
+ }
- endView = PeerToPeerEndView(
- baseActivity,
- peerInstance.title,
- )
- endView.setInstance(
- peerInstance, MyApplication.isConnectedToInternet(baseActivity), false
- )
- binding.endViewContainer.removeAllViews()
- binding.endViewContainer.addView(endView)
- endView.clearPartsProgress(peerInstance)
+ private fun observeUploadProgress() {
+ viewModel.uploadProgress.observe(viewLifecycleOwner) { percent ->
+ viewModel.p2PSharedState.session?.let { session ->
+ endView.setUploadProgress(session.files.values.toList(), percent.toFloat())
+ }
}
}
-
-}
\ No newline at end of file
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index 47cf3f36b..aac22899a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -3,7 +3,6 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.lifecycleScope
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterManager
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
index 4a5205929..573af2234 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
@@ -12,31 +12,23 @@
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.material.progressindicator.LinearProgressIndicator;
-import com.hzontal.utils.MediaFile;
import org.horizontal.tella.mobile.R;
-import org.horizontal.tella.mobile.domain.entity.EntityStatus;
-import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile;
-import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus;
-import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance;
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus;
+import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile;
+import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus;
import org.horizontal.tella.mobile.util.FileUtil;
-import org.horizontal.tella.mobile.util.Util;
import org.hzontal.shared_ui.submission.SubmittingItem;
-import java.util.Objects;
+import java.util.List;
-/**
- * Created by wafa on 9/7/2025.
- */
public class PeerToPeerEndView extends FrameLayout {
- LinearLayout partsListView;
- TextView titleView;
- TextView formStatusTextView;
- TextView formSizeView;
- String title;
- LinearProgressIndicator totalProgress;
- long formSize = 0L;
- private PeerToPeerInstance instance;
+ private final LinearProgressIndicator totalProgress;
+ private final TextView titleView;
+ private final TextView formSizeView;
+ private LinearLayout partsListView;
+
+ private final String title;
private boolean previewUploaded;
public PeerToPeerEndView(Context context, String title) {
@@ -50,198 +42,128 @@ public PeerToPeerEndView(Context context, String title) {
totalProgress = findViewById(R.id.totalProgress);
formSizeView = findViewById(R.id.formSize);
-
- formStatusTextView = findViewById(R.id.form_status);
}
- public void setInstance(@NonNull PeerToPeerInstance instance, boolean offline, boolean previewUploaded) {
- this.instance = instance;
+ public void setFiles(List progressFiles, boolean offline, boolean previewUploaded) {
this.previewUploaded = previewUploaded;
- refreshInstance(offline);
- }
-
- public void refreshInstance(boolean offline) {
- if (this.instance == null) {
- return;
- }
-
- TextView formNameView = findViewById(R.id.title);
- formNameView.setText(Objects.requireNonNull(instance.getTitle()));
+ titleView.setText(title);
partsListView = findViewById(R.id.formPartsList);
partsListView.removeAllViews();
- for (FormMediaFile mediaFile : instance.getWidgetMediaFiles()) {
- partsListView.addView(createFormMediaFileItemView(mediaFile, offline));
- formSize += mediaFile.size;
- }
- setFormSizeLabel(instance, 0);
- uploadProgressVisibity(instance, offline);
- setUploadProgress(instance, 0);
- }
-
- void setFormSizeLabel(@NonNull PeerToPeerInstance instance, int percent) {
- String title;
- if (instance.getWidgetMediaFiles().isEmpty()) {
- title = getStatusLabel(instance.getStatus());
- formSizeView.setText(title);
- return;
- }
- switch (instance.getStatus()) {
- case SUBMITTED:
- title = getStatusLabel(instance.getStatus()) + "\n" +
- getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
- instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
- FileUtil.getFileSizeString(formSize);
- break;
- case PAUSED:
- title = getStatusLabel(instance.getStatus()) + "\n" +
- getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
- instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
- getTotalUploadedSize(instance) + "/" + FileUtil.getFileSizeString(formSize);
- break;
- case FINALIZED:
- case SUBMISSION_PENDING:
- case SUBMISSION_ERROR:
- title = getStatusLabel(instance.getStatus()) + "\n" +
- getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
- instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
- getTotalUploadedSize(instance) + "/" + FileUtil.getFileSizeString(formSize) + " " +
- getResources().getString(R.string.File_Uploaded);
- break;
- default:
- title = percent + "% " + getResources().getString(R.string.File_Uploaded) + "\n" +
- getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files,
- instance.getWidgetMediaFiles().size(), instance.getWidgetMediaFiles().size()) + ", " +
- getTotalUploadedSize(instance) + "/" + FileUtil.getFileSizeString(formSize) + " " +
- getResources().getString(R.string.File_Uploaded);
- break;
+ for (ProgressFile file : progressFiles) {
+ partsListView.addView(createProgressFileItemView(file, offline));
}
- formSizeView.setText(title);
+ uploadProgressVisibility(progressFiles, true);
+ setUploadProgress(progressFiles, 0f);
}
+ public void setUploadProgress(List progressFiles, float pct) {
+ if (pct < 0 || pct > 1) return;
- String getStatusLabel(EntityStatus status) {
- String title = "";
- if (status == EntityStatus.SUBMITTED) {
- title = "";
- //getResources().getString(R.string.File_Uploaded_on) + " " + Util.getDateTimeString(instance.getUpdated());
- } else if (status == EntityStatus.PAUSED) {
- title = getResources().getString(R.string.Paused_Report);
- } else if (status == EntityStatus.FINALIZED || instance.getStatus() == EntityStatus.SUBMISSION_PENDING || instance.getStatus() == EntityStatus.SUBMISSION_ERROR) {
- title = getResources().getString(R.string.Report_Waiting_For_Connection);
- }
- return title;
- }
+ int percentComplete = getTotalUploadedSizePercent(progressFiles);
- private void uploadProgressVisibity(PeerToPeerInstance instance, Boolean isOnline) {
- if (!isOnline || instance.getWidgetMediaFiles().isEmpty()) {
- totalProgress.setVisibility(GONE);
- return;
+ for (ProgressFile file : progressFiles) {
+ if (file.getStatus() == P2PFileStatus.FINISHED && file.getVaultFile() != null) {
+ SubmittingItem item = partsListView.findViewWithTag(file.getVaultFile().id);
+ if (item != null) item.setPartUploaded();
+ }
}
- if (instance.getStatus() == EntityStatus.SUBMITTED) {
- totalProgress.setVisibility(GONE);
- } else {
- totalProgress.setVisibility(VISIBLE);
- }
+ totalProgress.setProgressCompat(percentComplete, true);
+ setFormSizeLabel(progressFiles, percentComplete);
}
- public void setUploadProgress(PeerToPeerInstance instance, float pct) {
- if (pct < 0 || pct > 1) {
- return;
- }
- int percentComplete;
+ public void clearPartsProgress(List progressFiles, SessionStatus sessionStatus) {
+ for (ProgressFile file : progressFiles) {
+ if (file.getVaultFile() == null) continue;
- if (instance.getWidgetMediaFiles().size() > 1) {
- percentComplete = getTotalUploadedSizePercent(instance);
- } else {
- percentComplete = (int) (pct * 100);
+ SubmittingItem item = partsListView.findViewWithTag(file.getVaultFile().id);
+ if (item != null) {
+ if (sessionStatus == SessionStatus.FINISHED || file.getStatus() == P2PFileStatus.FINISHED) {
+ item.setPartUploaded();
+ } else {
+ item.setPartCleared();
+ }
+ }
}
+ }
- for (FormMediaFile mediaFile : instance.getWidgetMediaFiles()) {
- if (mediaFile.status == FormMediaFileStatus.SUBMITTED) {
- SubmittingItem item = partsListView.findViewWithTag(mediaFile.getVaultFile().id);
- item.setPartUploaded();
+ private int getTotalUploadedSizePercent(List progressFiles) {
+ long totalUploadedSize = 0;
+ long totalSize = 0;
+
+ for (ProgressFile file : progressFiles) {
+ totalUploadedSize += file.getBytesTransferred();
+ if (file.getVaultFile() != null) {
+ totalSize += file.getVaultFile().size;
}
}
- //Timber.d("***Test*** PCT " + pct + "\n getTotalUploadedSize " + getTotalUploadedSize(instance) + "\n FormSize " + formSize + "\n percentComplete " + percentComplete + " \n Math.round(percentComplete) " + Math.toIntExact(percentComplete));
- totalProgress.setProgressCompat(percentComplete, true);
- setFormSizeLabel(instance, percentComplete);
+ return totalSize > 0 ? Math.round((totalUploadedSize * 1f / totalSize) * 100) : 0;
}
- private int getTotalUploadedSizePercent(PeerToPeerInstance instance) {
- int totalUploadedSize = 0;
- for (FormMediaFile formMediaFile : instance.getWidgetMediaFiles()) {
- totalUploadedSize += formMediaFile.uploadedSize;
- }
- if (totalUploadedSize > 0) {
- float percent = ((float) (totalUploadedSize * 1.0) / formSize);
- return Math.round(percent * 100);
+ private void setFormSizeLabel(List files, int percent) {
+ int count = files.size();
+ long totalSize = 0;
+ long totalUploaded = 0;
- } else {
- return 0;
+ for (ProgressFile file : files) {
+ if (file.getVaultFile() != null) {
+ totalSize += file.getVaultFile().size;
+ }
+ totalUploaded += file.getBytesTransferred();
}
- }
- private String getTotalUploadedSize(PeerToPeerInstance instance) {
- long totalUploadedSize = 0;
- for (FormMediaFile formMediaFile : instance.getWidgetMediaFiles()) {
- totalUploadedSize += formMediaFile.uploadedSize;
- }
- return FileUtil.getFileSize(totalUploadedSize);
- }
+ String label = percent + "% " + getContext().getString(R.string.File_Uploaded) + "\n" +
+ getResources().getQuantityString(R.plurals.upload_main_meta_number_of_files, count, count) + ", " +
+ FileUtil.getFileSize(totalUploaded) + "/" + FileUtil.getFileSize(totalSize);
- public void clearPartsProgress(PeerToPeerInstance instance) {
- setPartsCleared(instance);
+ formSizeView.setText(label);
}
+ private void uploadProgressVisibility(List files, boolean isOnline) {
+ if (!isOnline || files.isEmpty()) {
+ totalProgress.setVisibility(GONE);
+ } else {
+ totalProgress.setVisibility(VISIBLE);
+ }
+ }
- private View createFormMediaFileItemView(@NonNull FormMediaFile mediaFile, boolean offline) {
-
+ private View createProgressFileItemView(@NonNull ProgressFile file, boolean offline) {
SubmittingItem item = new SubmittingItem(getContext(), null, 0);
ImageView thumbView = item.findViewById(R.id.fileThumb);
- item.setTag(mediaFile.getPartName());
+ item.setTag(file.getVaultFile() != null ? file.getVaultFile().id : file.getFile().getId());
- item.setPartName(mediaFile.name);
- item.setPartSize(mediaFile.size);
+ item.setPartName(file.getFile().getFileName());
+ item.setPartSize(file.getFile().getSize());
- if (MediaFile.INSTANCE.isImageFileType(mediaFile.mimeType) || (MediaFile.INSTANCE.isVideoFileType(mediaFile.mimeType))) {
+ if (file.getVaultFile() != null && file.getVaultFile().thumb != null) {
Glide.with(getContext())
- .load(mediaFile.thumb)
+ .load(file.getVaultFile().thumb)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(thumbView);
- } else if (MediaFile.INSTANCE.isAudioFileType(mediaFile.mimeType)) {
- item.setPartIcon(R.drawable.ic_headset_white_24dp);
- } else {
- item.setPartIcon(R.drawable.ic_attach_file_white_24dp);
}
- if (mediaFile.status == FormMediaFileStatus.SUBMITTED || previewUploaded) {
- item.setPartUploaded();
- } else {
- item.setPartPrepared(offline);
+ switch (file.getStatus()) {
+ case FINISHED:
+ item.setPartUploaded();
+ break;
+ case FAILED:
+ case QUEUE:
+ case SENDING:
+ if (previewUploaded) {
+ item.setPartUploaded();
+ } else {
+ item.setPartPrepared(offline);
+ }
+ break;
}
return item;
}
-
- private void setPartsCleared(PeerToPeerInstance instance) {
- for (FormMediaFile mediaFile : instance.getWidgetMediaFiles()) {
- SubmittingItem item = partsListView.findViewWithTag(mediaFile.getVaultFile().id);
-
- if (instance.getStatus() == EntityStatus.SUBMITTED) {
- item.setPartUploaded();
- } else {
- item.setPartCleared();
- }
- }
- }
}
-
-
From 041f4f3ddb92b6e008a533c2fd2fdf187365be8a Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Sun, 13 Jul 2025 18:02:29 +0100
Subject: [PATCH 070/153] Fix reciepient fragment
---
.../RecipientUploadFilesFragment.kt | 45 +++++++++++--------
1 file changed, 26 insertions(+), 19 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index c34356e72..57727d1d2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -3,41 +3,48 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
+import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.MyApplication
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
+import javax.inject.Inject
-class RecipientUploadFilesFragment:
+@AndroidEntryPoint
+class RecipientUploadFilesFragment :
BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
private val viewModel: FileTransferViewModel by activityViewModels()
+
+ @Inject
+ lateinit var p2PSharedState: P2PSharedState
+
private lateinit var endView: PeerToPeerEndView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
showFormEndView()
+ observeUploadProgress()
}
private fun showFormEndView() {
- if (viewModel.peerToPeerInstance == null) {
- return
- }
-
- viewModel.peerToPeerInstance?.let { peerInstance ->
-
- endView = PeerToPeerEndView(
- baseActivity,
- peerInstance.title,
- )
- endView.setInstance(
- peerInstance, MyApplication.isConnectedToInternet(baseActivity), false
- )
- binding.endViewContainer.removeAllViews()
- binding.endViewContainer.addView(endView)
- endView.clearPartsProgress(peerInstance)
- }
+ val session = p2PSharedState.session ?: return
+ val files = session.files.values.toList()
+
+ endView = PeerToPeerEndView(
+ baseActivity,
+ session.title
+ )
+
+ endView.setFiles(files, MyApplication.isConnectedToInternet(baseActivity), false)
+
+ binding.endViewContainer.removeAllViews()
+ binding.endViewContainer.addView(endView)
}
-}
\ No newline at end of file
+ private fun observeUploadProgress() {
+
+ }
+}
From 7952e5c5d215f3d1993b1eefd6715097cf11b238 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Mon, 14 Jul 2025 10:52:58 +0100
Subject: [PATCH 071/153] change viewmodel package
---
.../receipentflow/ConnectHotspotFragment.kt | 2 +-
.../receipentflow/QRCodeFragment.kt | 2 +-
.../receipentflow/RecipientSuccessFragment.kt | 3 +-
.../RecipientUploadFilesFragment.kt | 2 +-
.../RecipientVerificationFragment.kt | 2 +-
.../receipentflow/ShowDeviceInfoFragment.kt | 2 +-
.../receipentflow/WaitingReceiverFragment.kt | 2 +-
.../senderflow/PrepareUploadFragment.kt | 2 +-
.../senderflow/ScanQrCodeFragment.kt | 2 +-
.../SenderManualConnectionFragment.kt | 2 +-
.../senderflow/SenderUploadFilesFragment.kt | 5 ++-
.../senderflow/SenderVerificationFragment.kt | 2 +-
.../senderflow/WaitingSenderFragment.kt | 2 +-
.../{ => viewmodel}/FileTransferViewModel.kt | 41 +++----------------
.../{ => viewmodel}/PeerToPeerViewModel.kt | 5 +--
15 files changed, 23 insertions(+), 53 deletions(-)
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/{ => viewmodel}/FileTransferViewModel.kt (79%)
rename mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/{ => viewmodel}/PeerToPeerViewModel.kt (97%)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index 957ab1c06..effbcbb2b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -17,7 +17,7 @@ import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.ConnectHotspotLayoutBinding
import org.horizontal.tella.mobile.util.ConnectionType
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
@AndroidEntryPoint
class ConnectHotspotFragment :
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 2cc88d231..641ee4be0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -19,7 +19,7 @@ import org.horizontal.tella.mobile.databinding.FragmentQrCodeBinding
import org.horizontal.tella.mobile.domain.peertopeer.KeyStoreConfig
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import javax.inject.Inject
@AndroidEntryPoint
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
index 935e2215b..19285a140 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientSuccessFragment.kt
@@ -7,8 +7,7 @@ import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentRecipientSuccessBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
-import org.hzontal.shared_ui.utils.DialogUtils
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
/**
* Created by wafa on 3/6/2025.
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index 57727d1d2..b71cc5d94 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -8,7 +8,7 @@ import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
import javax.inject.Inject
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index c13de8e9e..3f8911e89 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -14,7 +14,7 @@ import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBindin
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.util.formatHash
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import javax.inject.Inject
class RecipientVerificationFragment :
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 152537624..1ae6175b0 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -9,7 +9,7 @@ import kotlinx.coroutines.launch
import org.horizontal.tella.mobile.databinding.ShowDeviceInfoLayoutBinding
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
class ShowDeviceInfoFragment :
BaseBindingFragment(ShowDeviceInfoLayoutBinding::inflate) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
index 990714528..e9d396242 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/WaitingReceiverFragment.kt
@@ -7,7 +7,7 @@ import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import org.hzontal.shared_ui.utils.DialogUtils
/**
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 0ce5648b7..5c086f855 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -31,7 +31,7 @@ import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_AUDIO
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BUNDLE_REPORT_VAULT_FILE
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.OnNavBckListener
-import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.recorder.MicActivity
import org.horizontal.tella.mobile.views.fragment.recorder.REPORT_ENTRY
import org.horizontal.tella.mobile.views.fragment.uwazi.attachments.AttachmentsActivitySelector
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index ec29dd40d..19b98806f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -15,7 +15,7 @@ import com.journeyapps.barcodescanner.CompoundBarcodeView
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.databinding.ScanQrcodeFragmentBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
class ScanQrCodeFragment :
BaseBindingFragment(ScanQrcodeFragmentBinding::inflate) {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index f7663304d..3e70b8168 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -7,7 +7,7 @@ import androidx.fragment.app.activityViewModels
import com.hzontal.tella_locking_ui.common.extensions.onChange
import org.horizontal.tella.mobile.databinding.SenderManualConnectionBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import org.hzontal.shared_ui.bottomsheet.KeyboardUtil
// TODO: Show errors in the bottom sheet
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index 585a088e2..306cb43bf 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -6,7 +6,7 @@ import androidx.fragment.app.activityViewModels
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
class SenderUploadFilesFragment :
@@ -19,6 +19,9 @@ class SenderUploadFilesFragment :
super.onViewCreated(view, savedInstanceState)
showFormEndView()
observeUploadProgress()
+ viewModel.uploadAllFiles {
+
+ }
}
private fun showFormEndView() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
index aac22899a..e5468e659 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderVerificationFragment.kt
@@ -8,7 +8,7 @@ import org.horizontal.tella.mobile.data.peertopeer.managers.PeerServerStarterMan
import org.horizontal.tella.mobile.databinding.ConnectManuallyVerificationBinding
import org.horizontal.tella.mobile.util.formatHash
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.PeerToPeerViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import javax.inject.Inject
class SenderVerificationFragment :
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
index a4b801f05..b0c6bc408 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
@@ -7,7 +7,7 @@ import androidx.navigation.fragment.findNavController
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentWaitingBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.FileTransferViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.FileTransferViewModel
/**
* Created by wafa on 3/6/2025.
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
similarity index 79%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
index 88ac3b764..b4fe0b659 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
@@ -1,4 +1,4 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer
+package org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
@@ -18,9 +18,6 @@ import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadResult
-import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFile
-import org.horizontal.tella.mobile.domain.entity.collect.FormMediaFileStatus
-import org.horizontal.tella.mobile.domain.entity.peertopeer.PeerToPeerInstance
import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.Event
@@ -38,7 +35,6 @@ class FileTransferViewModel @Inject constructor(
val prepareResults: LiveData = _prepareResults
private val _prepareRejected = MutableLiveData>()
val prepareRejected: LiveData> = _prepareRejected
- var peerToPeerInstance: PeerToPeerInstance? = null
private val _uploadProgress = MutableLiveData() // value from 0 to 100
val uploadProgress: LiveData get() = _uploadProgress
@@ -64,24 +60,6 @@ class FileTransferViewModel @Inject constructor(
.subscribeOn(Schedulers.io())
}
- fun mediaFilesToVaultFiles(files: List?): List {
- val vaultFiles = ArrayList()
- files?.map { mediaFile ->
- vaultFiles.add(mediaFile.vaultFile)
- }
- return vaultFiles
- }
-
- fun vaultFilesToMediaFiles(files: List): List {
- val vaultFiles = mutableListOf()
- files.map { vaultFile ->
- val mediaFile = FormMediaFile.fromMediaFile(vaultFile)
- mediaFile.status = FormMediaFileStatus.NOT_SUBMITTED
- vaultFiles.add(FormMediaFile.fromMediaFile(vaultFile))
- }
- return vaultFiles
- }
-
fun prepareUploadsFromVaultFiles() {
viewModelScope.launch {
@@ -94,14 +72,6 @@ class FileTransferViewModel @Inject constructor(
sessionId = getSessionId()
)) {
is PrepareUploadResult.Success -> {
- val fileInfoMap = result.transmissions.associateBy { it.id }
-
- peerToPeerInstance?.widgetMediaFiles?.forEach { mediaFile ->
- fileInfoMap[mediaFile.id]?.let { fileInfo ->
- mediaFile.transmissionId = fileInfo.transmissionId
- }
- }
-
_prepareResults.postValue(PeerPrepareUploadResponse(result.transmissions))
}
@@ -132,7 +102,7 @@ class FileTransferViewModel @Inject constructor(
}
- fun uploadAllFiles(onFileUploaded: () -> Unit) {
+ fun uploadAllFiles() {
viewModelScope.launch {
val session = p2PSharedState.session ?: return@launch
val ip = p2PSharedState.ip
@@ -143,7 +113,8 @@ class FileTransferViewModel @Inject constructor(
session.files.values.forEach { progressFile ->
val vaultFile = progressFile.vaultFile ?: return@forEach
- val inputStream =MediaFileHandler.getStream(vaultFile) // Use your actual method here to get InputStream
+ val inputStream =
+ MediaFileHandler.getStream(vaultFile)
progressFile.status = P2PFileStatus.SENDING
@@ -162,13 +133,13 @@ class FileTransferViewModel @Inject constructor(
progressFile.bytesTransferred = written.toInt()
val uploaded = session.files.values.sumOf { it.bytesTransferred }
- val percent = if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
+ val percent =
+ if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
_uploadProgress.postValue(percent)
}
}
progressFile.status = P2PFileStatus.FINISHED
- onFileUploaded()
} catch (e: Exception) {
progressFile.status = P2PFileStatus.FAILED
Timber.e(e, "Upload failed for file ${progressFile.file.fileName}")
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
similarity index 97%
rename from mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
rename to mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index 0779e73a8..f12860d55 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -1,10 +1,9 @@
-package org.horizontal.tella.mobile.views.fragment.peertopeer
+package org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel
import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -18,7 +17,6 @@ import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
-import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
@@ -26,7 +24,6 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
import timber.log.Timber
-import java.util.UUID
import javax.inject.Inject
@HiltViewModel
From 5a746577c8d4fbec3fa5b9b5286b13f3d03f63b3 Mon Sep 17 00:00:00 2001
From: wafa
Date: Mon, 14 Jul 2025 19:00:05 +0100
Subject: [PATCH 072/153] fix location display for wifi display
---
.../receipentflow/ConnectHotspotFragment.kt | 88 +++++++++++--------
.../senderflow/SenderUploadFilesFragment.kt | 4 +-
2 files changed, 51 insertions(+), 41 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index effbcbb2b..13e243ec4 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -3,19 +3,31 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.ACCESS_NETWORK_STATE
import android.Manifest.permission.ACCESS_WIFI_STATE
+import android.app.AlertDialog
+import android.content.Context
+import android.content.Intent
+import android.content.IntentSender
import android.content.pm.PackageManager
+import android.location.LocationManager
import android.os.Build
import android.os.Bundle
+import android.provider.Settings
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
+import com.google.android.datatransport.Priority
+import com.google.android.gms.common.api.ResolvableApiException
+import com.google.android.gms.location.LocationRequest
+import com.google.android.gms.location.LocationServices
+import com.google.android.gms.location.LocationSettingsRequest
import com.hzontal.tella_locking_ui.ui.pin.pinview.ResourceUtils.getColor
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.ConnectHotspotLayoutBinding
import org.horizontal.tella.mobile.util.ConnectionType
+import org.horizontal.tella.mobile.util.LocationProvider.isLocationEnabled
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
@@ -25,19 +37,14 @@ class ConnectHotspotFragment :
private val viewModel: PeerToPeerViewModel by activityViewModels()
private var isCheckboxChecked = false
- private val permissionsToRequest = mutableListOf()
@RequiresApi(Build.VERSION_CODES.M)
private val requestPermissionLauncher =
- registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
- val fineLocationGranted = permissions[ACCESS_FINE_LOCATION] ?: false
- val wifiStateGranted = permissions[ACCESS_WIFI_STATE] ?: false
- val networkStateGranted = permissions[ACCESS_NETWORK_STATE] ?: false
-
- if (fineLocationGranted && wifiStateGranted && networkStateGranted) {
- viewModel.updateNetworkInfo()
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
+ if (granted) {
+ checkLocationSettings()
} else {
- baseActivity.showToast("Location and network permissions are required to get WiFi SSID.")
+ baseActivity.showToast("Location permission is required to get WiFi SSID.")
}
}
@@ -47,7 +54,6 @@ class ConnectHotspotFragment :
initObservers()
initListeners()
checkAndRequestPermissions()
- updateInfoOrGetPermission()
}
private fun initObservers() {
@@ -88,6 +94,7 @@ class ConnectHotspotFragment :
} else {
{ }
})
+
binding.nextBtn.setTextColor(
getColor(baseActivity, if (shouldEnable) R.color.wa_white else R.color.wa_white_40)
)
@@ -100,38 +107,43 @@ class ConnectHotspotFragment :
@RequiresApi(Build.VERSION_CODES.M)
private fun checkAndRequestPermissions() {
-
- if (ContextCompat.checkSelfPermission(
- baseActivity,
- ACCESS_FINE_LOCATION
- ) != PackageManager.PERMISSION_GRANTED
- ) {
- permissionsToRequest.add(ACCESS_FINE_LOCATION)
- }
- if (ContextCompat.checkSelfPermission(
- baseActivity,
- ACCESS_WIFI_STATE
- ) != PackageManager.PERMISSION_GRANTED
+ if (ContextCompat.checkSelfPermission(baseActivity, ACCESS_FINE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED
) {
- permissionsToRequest.add(ACCESS_WIFI_STATE)
- }
- if (ContextCompat.checkSelfPermission(
- baseActivity,
- ACCESS_NETWORK_STATE
- ) != PackageManager.PERMISSION_GRANTED
- ) {
- permissionsToRequest.add(ACCESS_NETWORK_STATE)
+ baseActivity.maybeChangeTemporaryTimeout{
+ requestPermissionLauncher.launch(ACCESS_FINE_LOCATION)
+ }
+ } else {
+ checkLocationSettings()
}
}
- @RequiresApi(Build.VERSION_CODES.M)
- private fun updateInfoOrGetPermission() {
- if (permissionsToRequest.isNotEmpty()) {
- baseActivity.maybeChangeTemporaryTimeout {
- requestPermissionLauncher.launch(permissionsToRequest.toTypedArray())
+ private fun checkLocationSettings() {
+ val locationRequest = LocationRequest.create()
+ .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
+
+ val builder = LocationSettingsRequest.Builder()
+ .addLocationRequest(locationRequest)
+ .setAlwaysShow(true)
+
+ val settingsClient = LocationServices.getSettingsClient(requireActivity())
+ settingsClient.checkLocationSettings(builder.build())
+ .addOnSuccessListener {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ viewModel.updateNetworkInfo()
+ }
+ }
+ .addOnFailureListener { exception ->
+ if (exception is ResolvableApiException) {
+ try {
+ exception.startResolutionForResult(requireActivity(), 1001)
+ } catch (sendEx: IntentSender.SendIntentException) {
+ baseActivity.showToast("Failed to open location settings.")
+ }
+ } else {
+ baseActivity.showToast("Location services are required to get WiFi SSID.")
+ }
}
- } else {
- viewModel.updateNetworkInfo()
- }
}
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index 306cb43bf..d6740ff10 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -19,9 +19,7 @@ class SenderUploadFilesFragment :
super.onViewCreated(view, savedInstanceState)
showFormEndView()
observeUploadProgress()
- viewModel.uploadAllFiles {
-
- }
+ viewModel.uploadAllFiles()
}
private fun showFormEndView() {
From c060dc42c4f27961eb91a25da1ebb47129da1d4a Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 15 Jul 2025 11:55:43 +0100
Subject: [PATCH 073/153] add error handling in registration flow
---
.../receipentflow/ConnectHotspotFragment.kt | 6 ++--
.../receipentflow/QRCodeFragment.kt | 2 --
.../receipentflow/ShowDeviceInfoFragment.kt | 1 -
.../SenderManualConnectionFragment.kt | 20 +++++++++++--
.../viewmodel/PeerToPeerViewModel.kt | 28 +++++++++++--------
mobile/src/main/res/values-ar/strings.xml | 2 ++
mobile/src/main/res/values-be/strings.xml | 2 ++
mobile/src/main/res/values-blk/strings.xml | 2 ++
mobile/src/main/res/values-bn/strings.xml | 2 ++
mobile/src/main/res/values-es-rCU/strings.xml | 2 ++
mobile/src/main/res/values-es/strings.xml | 2 ++
mobile/src/main/res/values-fa-rIR/strings.xml | 2 ++
mobile/src/main/res/values-fr/strings.xml | 2 ++
mobile/src/main/res/values-hdpi/strings.xml | 2 ++
mobile/src/main/res/values-in/strings.xml | 2 ++
mobile/src/main/res/values-kac/strings.xml | 2 ++
mobile/src/main/res/values-kn/strings.xml | 2 ++
mobile/src/main/res/values-ksw/strings.xml | 2 ++
mobile/src/main/res/values-ku/strings.xml | 2 ++
mobile/src/main/res/values-mdpi/strings.xml | 2 ++
mobile/src/main/res/values-ml/strings.xml | 2 ++
mobile/src/main/res/values-my/strings.xml | 2 ++
mobile/src/main/res/values-ndc/strings.xml | 2 ++
mobile/src/main/res/values-pt-rMZ/strings.xml | 2 ++
mobile/src/main/res/values-pt/strings.xml | 2 ++
mobile/src/main/res/values-ru/strings.xml | 2 ++
mobile/src/main/res/values-sn-rZW/strings.xml | 2 ++
.../src/main/res/values-sw600dp/strings.xml | 2 ++
mobile/src/main/res/values-ta/strings.xml | 2 ++
mobile/src/main/res/values-tr/strings.xml | 2 ++
mobile/src/main/res/values-ts/strings.xml | 2 ++
mobile/src/main/res/values-v21/strings.xml | 2 ++
mobile/src/main/res/values-v26/strings.xml | 2 ++
mobile/src/main/res/values-vi/strings.xml | 2 ++
mobile/src/main/res/values-w820dp/strings.xml | 2 ++
mobile/src/main/res/values-xhdpi/strings.xml | 2 ++
mobile/src/main/res/values-xxhdpi/strings.xml | 2 ++
mobile/src/main/res/values/strings.xml | 3 ++
38 files changed, 105 insertions(+), 19 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index 13e243ec4..c14b50ef8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -44,7 +44,7 @@ class ConnectHotspotFragment :
if (granted) {
checkLocationSettings()
} else {
- baseActivity.showToast("Location permission is required to get WiFi SSID.")
+ baseActivity.showToast(getString(R.string.location_permission_is_required_to_get_wifi_ssid))
}
}
@@ -138,10 +138,10 @@ class ConnectHotspotFragment :
try {
exception.startResolutionForResult(requireActivity(), 1001)
} catch (sendEx: IntentSender.SendIntentException) {
- baseActivity.showToast("Failed to open location settings.")
+ baseActivity.showToast(getString(R.string.failed_to_open_location_settings))
}
} else {
- baseActivity.showToast("Location services are required to get WiFi SSID.")
+ baseActivity.showToast(getString(R.string.location_permission_is_required_to_get_wifi_ssid))
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
index 641ee4be0..019ce6928 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/QRCodeFragment.kt
@@ -53,7 +53,6 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
// Navigate to the next screen
- // bundle.putBoolean("isSender", false)
navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
// reset the LiveData state if we want to consume event once
viewModel.resetRegistrationState()
@@ -134,7 +133,6 @@ class QRCodeFragment : BaseBindingFragment(FragmentQrCode
private fun initObservers() {
viewModel.registrationSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
- bundle.putBoolean("isSender", false)
navManager().navigateFromQrCodeScreenToWaitingReceiverFragment()
} else {
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
index 1ae6175b0..831264498 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ShowDeviceInfoFragment.kt
@@ -55,7 +55,6 @@ class ShowDeviceInfoFragment :
viewModel.registrationServerSuccess.observe(viewLifecycleOwner) { success ->
if (success) {
// Navigate to the next screen
- // bundle.putBoolean("isSender", false)
navManager().navigateFromWaitingReceiverFragmentToRecipientSuccessFragment()
// reset the LiveData state if we want to consume event once
viewModel.resetRegistrationState()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index 3e70b8168..b779be8f9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -5,10 +5,14 @@ import android.view.View
import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
import com.hzontal.tella_locking_ui.common.extensions.onChange
+import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.SenderManualConnectionBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
+import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils
+import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils.showStandardSheet
import org.hzontal.shared_ui.bottomsheet.KeyboardUtil
+import org.hzontal.shared_ui.utils.DialogUtils
// TODO: Show errors in the bottom sheet
class SenderManualConnectionFragment :
@@ -56,9 +60,21 @@ class SenderManualConnectionFragment :
bundle.putString("payload", hash)
navManager().navigateFromSenderManualConnectionToConnectManuallyVerification()
}
+ viewModel.bottomMessageError.observe(viewLifecycleOwner) { message ->
+ DialogUtils.showBottomMessage(baseActivity, message, true)
+ }
- viewModel.getHashError.observe(viewLifecycleOwner) { error ->
- error.localizedMessage?.let { showToast(it) }
+ viewModel.bottomSheetError.observe(viewLifecycleOwner) { (title, description) ->
+ showStandardSheet(
+ baseActivity.supportFragmentManager,
+ title,
+ description,
+ null,
+ getString(R.string.try_again),
+ null
+ ) {
+ activity?.onBackPressed()
+ }
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index f12860d55..3c9fe6dff 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -41,8 +41,8 @@ class PeerToPeerViewModel @Inject constructor(
val registrationSuccess: LiveData get() = _registrationSuccess
private val _getHashSuccess = SingleLiveEvent()
val getHashSuccess: LiveData get() = _getHashSuccess
- private val _getHashError = SingleLiveEvent()
- val getHashError: LiveData get() = _getHashError
+ val bottomMessageError = SingleLiveEvent()
+ val bottomSheetError = SingleLiveEvent>()
val clientHash = peerToPeerManager.clientConnected
private val _registrationServerSuccess = SingleLiveEvent()
val registrationServerSuccess: LiveData = _registrationServerSuccess
@@ -110,32 +110,35 @@ class PeerToPeerViewModel @Inject constructor(
}
RegisterPeerResult.InvalidPin -> {
- _getHashError.postValue(Exception("Invalid PIN"))
+ bottomMessageError.postValue("Invalid PIN")
}
RegisterPeerResult.InvalidFormat -> {
- _getHashError.postValue(Exception("Invalid request format"))
+ bottomMessageError.postValue("Invalid request format")
}
RegisterPeerResult.Conflict -> {
- _getHashError.postValue(Exception("Active session already exists"))
+ bottomMessageError.postValue("Active session already exists")
}
RegisterPeerResult.TooManyRequests -> {
- _getHashError.postValue(Exception("Too many requests, try again later"))
+ bottomMessageError.postValue("Too many requests, try again later")
}
RegisterPeerResult.ServerError -> {
- _getHashError.postValue(Exception("Server error, try again later"))
+ bottomMessageError.postValue("Server error, try again later")
}
RegisterPeerResult.RejectedByReceiver -> {
- _getHashError.postValue(Exception("Receiver rejected the registration"))
+ bottomMessageError.postValue("Receiver rejected the registration")
}
is RegisterPeerResult.Failure -> {
- Timber.e(result.exception, "Registration failed")
- _getHashError.postValue(result.exception)
+ Timber.e(result.exception, "Connection failure")
+ bottomSheetError.postValue(
+ "Connection failed" to
+ "Please make sure your connection details are correct and that you are on the same Wi-Fi network."
+ )
}
}
}
@@ -159,7 +162,10 @@ class PeerToPeerViewModel @Inject constructor(
}.onFailure { error ->
Timber.d("error ***** $error")
- _getHashError.postValue(error)
+ bottomSheetError.postValue(
+ "Connection failed" to
+ "Please make sure your connection details are correct and that you are on the same Wi-Fi network."
+ )
}
}
}
diff --git a/mobile/src/main/res/values-ar/strings.xml b/mobile/src/main/res/values-ar/strings.xml
index 47293ef16..26aba9d01 100644
--- a/mobile/src/main/res/values-ar/strings.xml
+++ b/mobile/src/main/res/values-ar/strings.xml
@@ -1003,4 +1003,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-be/strings.xml b/mobile/src/main/res/values-be/strings.xml
index cd0b91ffc..02908261b 100644
--- a/mobile/src/main/res/values-be/strings.xml
+++ b/mobile/src/main/res/values-be/strings.xml
@@ -1004,4 +1004,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-blk/strings.xml b/mobile/src/main/res/values-blk/strings.xml
index 2a313d4cb..5ea8e3ff1 100644
--- a/mobile/src/main/res/values-blk/strings.xml
+++ b/mobile/src/main/res/values-blk/strings.xml
@@ -142,4 +142,6 @@
Your feedback has been sent
share feedback
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-bn/strings.xml b/mobile/src/main/res/values-bn/strings.xml
index 0dbe34939..25ee1f8f2 100644
--- a/mobile/src/main/res/values-bn/strings.xml
+++ b/mobile/src/main/res/values-bn/strings.xml
@@ -984,4 +984,6 @@
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-es-rCU/strings.xml b/mobile/src/main/res/values-es-rCU/strings.xml
index 4a0dae9f7..77c3e374f 100644
--- a/mobile/src/main/res/values-es-rCU/strings.xml
+++ b/mobile/src/main/res/values-es-rCU/strings.xml
@@ -1005,4 +1005,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-es/strings.xml b/mobile/src/main/res/values-es/strings.xml
index 3386c00f5..7fe505fa4 100644
--- a/mobile/src/main/res/values-es/strings.xml
+++ b/mobile/src/main/res/values-es/strings.xml
@@ -988,4 +988,6 @@ Este feedback es anónimo, así que asegúrate de incluir tu información de con
Adjuntar archivo
%1$s eviado correctamente
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-fa-rIR/strings.xml b/mobile/src/main/res/values-fa-rIR/strings.xml
index a35c05c72..68d5d66b6 100644
--- a/mobile/src/main/res/values-fa-rIR/strings.xml
+++ b/mobile/src/main/res/values-fa-rIR/strings.xml
@@ -1001,4 +1001,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-fr/strings.xml b/mobile/src/main/res/values-fr/strings.xml
index 92a94193d..7dbf91262 100644
--- a/mobile/src/main/res/values-fr/strings.xml
+++ b/mobile/src/main/res/values-fr/strings.xml
@@ -998,4 +998,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-hdpi/strings.xml b/mobile/src/main/res/values-hdpi/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-hdpi/strings.xml
+++ b/mobile/src/main/res/values-hdpi/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values-in/strings.xml b/mobile/src/main/res/values-in/strings.xml
index 5eb7d714a..e64827853 100644
--- a/mobile/src/main/res/values-in/strings.xml
+++ b/mobile/src/main/res/values-in/strings.xml
@@ -986,4 +986,6 @@ Apakah Anda ingin membagikan analitik kepada tim Tella?
Lampirkan berkas
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-kac/strings.xml b/mobile/src/main/res/values-kac/strings.xml
index ca83e630b..6e755dcd0 100644
--- a/mobile/src/main/res/values-kac/strings.xml
+++ b/mobile/src/main/res/values-kac/strings.xml
@@ -1004,4 +1004,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-kn/strings.xml b/mobile/src/main/res/values-kn/strings.xml
index 68cb63707..6681f7b22 100644
--- a/mobile/src/main/res/values-kn/strings.xml
+++ b/mobile/src/main/res/values-kn/strings.xml
@@ -1004,4 +1004,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-ksw/strings.xml b/mobile/src/main/res/values-ksw/strings.xml
index e2d812a15..ef08d50d1 100644
--- a/mobile/src/main/res/values-ksw/strings.xml
+++ b/mobile/src/main/res/values-ksw/strings.xml
@@ -987,4 +987,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-ku/strings.xml b/mobile/src/main/res/values-ku/strings.xml
index 88200b941..911593d8d 100644
--- a/mobile/src/main/res/values-ku/strings.xml
+++ b/mobile/src/main/res/values-ku/strings.xml
@@ -999,4 +999,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-mdpi/strings.xml b/mobile/src/main/res/values-mdpi/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-mdpi/strings.xml
+++ b/mobile/src/main/res/values-mdpi/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ml/strings.xml b/mobile/src/main/res/values-ml/strings.xml
index 8be73fa59..66403f6c3 100644
--- a/mobile/src/main/res/values-ml/strings.xml
+++ b/mobile/src/main/res/values-ml/strings.xml
@@ -1004,4 +1004,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-my/strings.xml b/mobile/src/main/res/values-my/strings.xml
index 0a23a7884..e23266056 100644
--- a/mobile/src/main/res/values-my/strings.xml
+++ b/mobile/src/main/res/values-my/strings.xml
@@ -987,4 +987,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-ndc/strings.xml b/mobile/src/main/res/values-ndc/strings.xml
index e10faa1c3..826c63970 100644
--- a/mobile/src/main/res/values-ndc/strings.xml
+++ b/mobile/src/main/res/values-ndc/strings.xml
@@ -978,4 +978,6 @@ Wainda kupaurirana maonere no chikwatha Tella?
Kuisa gwaro mapwepo
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-pt-rMZ/strings.xml b/mobile/src/main/res/values-pt-rMZ/strings.xml
index a18e9217f..4e8d3e6f3 100644
--- a/mobile/src/main/res/values-pt-rMZ/strings.xml
+++ b/mobile/src/main/res/values-pt-rMZ/strings.xml
@@ -990,4 +990,6 @@ Gostaria de partilhar dados com a equipa do Tella?
Anexar arquivo
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-pt/strings.xml b/mobile/src/main/res/values-pt/strings.xml
index c0bd0c369..cca390370 100644
--- a/mobile/src/main/res/values-pt/strings.xml
+++ b/mobile/src/main/res/values-pt/strings.xml
@@ -1004,4 +1004,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-ru/strings.xml b/mobile/src/main/res/values-ru/strings.xml
index 31a6be0bc..6dbfa6f3e 100644
--- a/mobile/src/main/res/values-ru/strings.xml
+++ b/mobile/src/main/res/values-ru/strings.xml
@@ -1014,4 +1014,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-sn-rZW/strings.xml b/mobile/src/main/res/values-sn-rZW/strings.xml
index e10faa1c3..826c63970 100644
--- a/mobile/src/main/res/values-sn-rZW/strings.xml
+++ b/mobile/src/main/res/values-sn-rZW/strings.xml
@@ -978,4 +978,6 @@ Wainda kupaurirana maonere no chikwatha Tella?
Kuisa gwaro mapwepo
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-sw600dp/strings.xml b/mobile/src/main/res/values-sw600dp/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-sw600dp/strings.xml
+++ b/mobile/src/main/res/values-sw600dp/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ta/strings.xml b/mobile/src/main/res/values-ta/strings.xml
index 9c5087049..5e59a8067 100644
--- a/mobile/src/main/res/values-ta/strings.xml
+++ b/mobile/src/main/res/values-ta/strings.xml
@@ -1004,4 +1004,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-tr/strings.xml b/mobile/src/main/res/values-tr/strings.xml
index 9dd131245..5a70fe746 100644
--- a/mobile/src/main/res/values-tr/strings.xml
+++ b/mobile/src/main/res/values-tr/strings.xml
@@ -984,4 +984,6 @@ Tella ekibiyle analizleri paylaşmak ister misiniz?
Dosya ekle
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-ts/strings.xml b/mobile/src/main/res/values-ts/strings.xml
index 3f77cd650..357000ae3 100644
--- a/mobile/src/main/res/values-ts/strings.xml
+++ b/mobile/src/main/res/values-ts/strings.xml
@@ -974,4 +974,6 @@ yi fanele ku ku nyika vutshokotshoko bya servhidor.
Nghenisa arkivho
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-v21/strings.xml b/mobile/src/main/res/values-v21/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-v21/strings.xml
+++ b/mobile/src/main/res/values-v21/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values-v26/strings.xml b/mobile/src/main/res/values-v26/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-v26/strings.xml
+++ b/mobile/src/main/res/values-v26/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values-vi/strings.xml b/mobile/src/main/res/values-vi/strings.xml
index 1285723ee..6bcd0bb37 100644
--- a/mobile/src/main/res/values-vi/strings.xml
+++ b/mobile/src/main/res/values-vi/strings.xml
@@ -994,4 +994,6 @@ Would you like to share analytics with the Tella team?
Attach file
%1$s successfully submitted
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
diff --git a/mobile/src/main/res/values-w820dp/strings.xml b/mobile/src/main/res/values-w820dp/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-w820dp/strings.xml
+++ b/mobile/src/main/res/values-w820dp/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xhdpi/strings.xml b/mobile/src/main/res/values-xhdpi/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-xhdpi/strings.xml
+++ b/mobile/src/main/res/values-xhdpi/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xxhdpi/strings.xml b/mobile/src/main/res/values-xxhdpi/strings.xml
index 67ac84b3d..8f72f3128 100644
--- a/mobile/src/main/res/values-xxhdpi/strings.xml
+++ b/mobile/src/main/res/values-xxhdpi/strings.xml
@@ -1,4 +1,6 @@
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index cefc0ca6a..55e34ebe5 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1054,4 +1054,7 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Receiving and encrypting files
Sending files
Send files
+ Location permission is required to get WiFi SSID.
+ Failed to open location settings.
+ Try again
From 549583518948b5c749d29e7e7094090da23f9e44 Mon Sep 17 00:00:00 2001
From: wafa
Date: Tue, 15 Jul 2025 12:00:41 +0100
Subject: [PATCH 074/153] wip recipient flow in upload
---
.../mobile/data/database/DataSource.java | 1 -
.../data/peertopeer/TellaPeerToPeerClient.kt | 15 ----
.../data/peertopeer/TellaPeerToPeerServer.kt | 76 +++++++++++++++++--
.../managers/PeerServerStarterManager.kt | 1 -
.../domain/peertopeer/PeerEventManager.kt | 49 +++++++++---
.../domain/peertopeer/PeerRegisterPayload.kt | 1 -
.../tella/mobile/media/MediaFileHandler.java | 1 +
.../activity/camera/SharedCameraViewModel.kt | 16 ++--
.../RecipientUploadFilesFragment.kt | 8 +-
.../RecipientVerificationFragment.kt | 1 -
.../viewmodel/FileTransferViewModel.kt | 1 -
.../viewmodel/PeerToPeerViewModel.kt | 10 ++-
.../attachements/AttachmentsViewModel.kt | 4 +-
13 files changed, 131 insertions(+), 53 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java b/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java
index f671bb596..c53a996e8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java
@@ -5,7 +5,6 @@
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 57accb6b7..6077e7a8e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -35,7 +35,6 @@ import javax.net.ssl.X509TrustManager
class TellaPeerToPeerClient @Inject constructor(){
-
private fun getClientWithFingerprintValidation(expectedFingerprint: String): OkHttpClient {
val trustManager = object : X509TrustManager {
override fun getAcceptedIssuers(): Array = arrayOf()
@@ -92,13 +91,6 @@ class TellaPeerToPeerClient @Inject constructor(){
return@use parseSessionIdFromResponse(body)
}
- Timber.w(
- """registerPeerDevice failed
- Status: ${response.code}
- URL: $url
- Body: $body""".trimIndent()
- )
-
return@use when (response.code) {
400 -> RegisterPeerResult.InvalidFormat
401 -> RegisterPeerResult.InvalidPin
@@ -179,11 +171,6 @@ class TellaPeerToPeerClient @Inject constructor(){
private fun parseTransmissionId(body: String): PrepareUploadResult {
return try {
val response = Json.decodeFromString(body)
-
- response.files.forEach {
- // PeerSessionManager.saveTransmissionId(it.id, it.transmissionId)
- }
-
PrepareUploadResult.Success(response.files)
} catch (e: Exception) {
Timber.e(e, "Invalid JSON response: %s", body)
@@ -240,6 +227,4 @@ class TellaPeerToPeerClient @Inject constructor(){
}
}
-
-
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 4d9fd7002..4c7f089d6 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -11,6 +11,7 @@ import io.ktor.server.engine.sslConnector
import io.ktor.server.netty.Netty
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.request.receive
+import io.ktor.server.request.receiveStream
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
@@ -19,10 +20,9 @@ import io.ktor.server.routing.routing
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import kotlinx.serialization.encodeToString
-import kotlinx.serialization.json.Json
import org.horizontal.tella.mobile.certificate.CertificateUtils
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
@@ -42,6 +42,7 @@ import java.util.UUID
const val port = 53317
+//TODO THIS CLASS MUST BE INJECTED
class TellaPeerToPeerServer(
private val ip: String,
private val serverPort: Int = port,
@@ -105,7 +106,6 @@ class TellaPeerToPeerServer(
return@post
}
- //TODO CHECK IF THE PIN IS CORRECT
if (!isValidPin(request.pin) || pin != request.pin) {
call.respond(HttpStatusCode.Unauthorized, "Invalid PIN")
return@post
@@ -116,11 +116,6 @@ class TellaPeerToPeerServer(
return@post
}
- // if (isRateLimited(...)) {
- // call.respond(HttpStatusCode.TooManyRequests, "Too many requests")
- // return@post
- // }
-
val sessionId = UUID.randomUUID().toString()
val session = PeerResponse(sessionId)
serverSession = session
@@ -195,12 +190,77 @@ class TellaPeerToPeerServer(
call.respond(HttpStatusCode.Forbidden, "Transfer rejected by receiver")
}
}
+
+ post(PeerApiRoutes.UPLOAD) {
+ val sessionId = call.parameters["sessionId"]
+ val fileId = call.parameters["fileId"]
+ val transmissionId = call.parameters["transmissionId"]
+
+ if (sessionId == null || fileId == null || transmissionId == null) {
+ call.respond(HttpStatusCode.BadRequest, "Missing path parameters")
+ return@post
+ }
+
+ if (sessionId != serverSession?.sessionId || sessionId != p2PSharedState.session?.sessionId) {
+ call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
+ return@post
+ }
+
+ val session = p2PSharedState.session
+ val progressFile = session?.files?.get(transmissionId)
+
+ if (progressFile == null || progressFile.file.id != fileId) {
+ call.respond(HttpStatusCode.NotFound, "File not found in session")
+ return@post
+ }
+
+ val tmpFile = createTempFile(prefix = "p2p_", suffix = "_$fileId")
+ val output = tmpFile.outputStream().buffered()
+
+ try {
+ val input = call.receiveStream().buffered()
+ val totalBytesExpected = progressFile.file.size
+ var bytesRead = 0L
+ val buffer = ByteArray(8192)
+
+ while (true) {
+ val read = input.read(buffer)
+ if (read == -1) break
+ output.write(buffer, 0, read)
+ bytesRead += read
+
+ progressFile.bytesTransferred = bytesRead.toInt()
+ PeerEventManager.onUploadProgressState(
+ p2PSharedState
+ )
+ }
+
+ progressFile.status = P2PFileStatus.FINISHED
+ progressFile.path = tmpFile.absolutePath
+
+
+ call.respond(HttpStatusCode.OK, "Upload complete")
+ } catch (e: Exception) {
+ progressFile.status = P2PFileStatus.FAILED
+ call.respond(HttpStatusCode.InternalServerError, "Upload failed: ${e.message}")
+ } finally {
+ output.close()
+ }
+ }
+
+
}
}
}).start(wait = false)
}
+ private fun calculatePercent(files: Collection): Int {
+ val uploaded = files.sumOf { it.bytesTransferred.toLong() }
+ val total = files.sumOf { it.file.size }
+ return if (total > 0) ((uploaded * 100) / total).toInt() else 0
+ }
+
override fun stop() {
engine?.stop(1000, 5000)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
index 3dc6c0b53..89794d12c 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/managers/PeerServerStarterManager.kt
@@ -39,7 +39,6 @@ class PeerServerStarterManager @Inject constructor(
}
}
- //TODO: AHLEM CHECK WHERE WE WANT TO STOP THE SERVER
fun stopServer() {
CoroutineScope(Dispatchers.IO).launch {
server?.stop()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
index 632a21f3c..dbdbc292a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
@@ -3,43 +3,67 @@ package org.horizontal.tella.mobile.domain.peertopeer
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
/**
* Created by wafa on 3/6/2025.
*/
object PeerEventManager {
- // MutableSharedFlow to emit registration events, replay 1 to send last event to new collectors
val registrationEvents = MutableSharedFlow(replay = 1)
- private val _registrationRequests = MutableSharedFlow>(replay = 1)
+ private val _registrationRequests =
+ MutableSharedFlow>(replay = 1)
val registrationRequests = _registrationRequests.asSharedFlow()
-
private val registrationDecisionMap = mutableMapOf>()
+ private val _prepareUploadEvents = MutableSharedFlow(replay = 1)
+ val prepareUploadEvents = _prepareUploadEvents.asSharedFlow()
+ private val decisionMap = mutableMapOf>()
+ private val _uploadProgressStateFlow = MutableSharedFlow(replay = 1)
+ val uploadProgressStateFlow = _uploadProgressStateFlow.asSharedFlow()
+
+
+ suspend fun onUploadProgressState(p2PSharedState : P2PSharedState) {
+ val session = p2PSharedState.session
+ val files = session?.files?.values?.toList() ?: emptyList()
+
+ val totalSize = files.sumOf { it.file.size }
+ val uploaded = files.sumOf { it.bytesTransferred }
+ val percent = if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
+
+ val state = session?.status?.let {
+ UploadProgressState(
+ percent = percent,
+ sessionStatus = it,
+ files = files
+ )
+ }
+
+ if (state != null) {
+ _uploadProgressStateFlow.emit(state)
+ }
+ }
- // Call this when registration succeeds
suspend fun emitRegistrationSuccess() {
registrationEvents.emit(true)
}
- // we can add emitRegistrationFailure or other event types if needed
- private val _prepareUploadEvents = MutableSharedFlow(replay = 1)
- val prepareUploadEvents = _prepareUploadEvents.asSharedFlow()
-
- private val decisionMap = mutableMapOf>()
-
suspend fun emitPrepareUploadRequest(request: PrepareUploadRequest): Boolean {
val deferred = CompletableDeferred()
decisionMap[request.sessionId] = deferred
_prepareUploadEvents.emit(request)
- return deferred.await() // Wait for UI decision
+ return deferred.await()
}
fun resolveUserDecision(sessionId: String, accepted: Boolean) {
decisionMap.remove(sessionId)?.complete(accepted)
}
- suspend fun emitIncomingRegistrationRequest(registrationId: String, payload: PeerRegisterPayload): Boolean {
+ suspend fun emitIncomingRegistrationRequest(
+ registrationId: String,
+ payload: PeerRegisterPayload
+ ): Boolean {
val deferred = CompletableDeferred()
registrationDecisionMap[registrationId] = deferred
_registrationRequests.emit(registrationId to payload)
@@ -49,4 +73,5 @@ object PeerEventManager {
fun confirmRegistration(registrationId: String, accepted: Boolean) {
registrationDecisionMap.remove(registrationId)?.complete(accepted)
}
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
index 9ae20e47e..4386df941 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerRegisterPayload.kt
@@ -7,5 +7,4 @@ import java.util.UUID
data class PeerRegisterPayload(
val pin: String,
val nonce: String = UUID.randomUUID().toString(),
- // val autoAccept: Boolean = false,
)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/media/MediaFileHandler.java b/mobile/src/main/java/org/horizontal/tella/mobile/media/MediaFileHandler.java
index d9bc46057..e2752f61d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/media/MediaFileHandler.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/media/MediaFileHandler.java
@@ -423,6 +423,7 @@ public static Single importOthersUri(Context context, Uri uri, String
assert DocumentFile.fromSingleUri(context, uri) != null;
RxVault rxVault = MyApplication.keyRxVault.getRxVault().blockingFirst();
+ assert DocumentFile.fromSingleUri(context, uri) != null;
return rxVault
.builder(is)
.setMimeType(mimeType)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/camera/SharedCameraViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/camera/SharedCameraViewModel.kt
index df9749e1d..65cb9f849 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/camera/SharedCameraViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/camera/SharedCameraViewModel.kt
@@ -62,7 +62,8 @@ class SharedCameraViewModel @Inject constructor() : ViewModel() {
thumb = null
)
_addingInProgress.postValue(true)
- MyApplication.bus().post(RecentBackgroundActivitiesEvent(mutableListOf(backgroundVideoFile)))
+ MyApplication.bus()
+ .post(RecentBackgroundActivitiesEvent(mutableListOf(backgroundVideoFile)))
}
.observeOn(AndroidSchedulers.mainThread())
.doFinally { _addingInProgress.postValue(false) }
@@ -75,7 +76,6 @@ class SharedCameraViewModel @Inject constructor() : ViewModel() {
)
}
-
fun addMp4Video(file: File, parent: String?) {
disposables.add(Observable.fromCallable { MediaFileHandler.saveMp4Video(file, parent) }
.subscribeOn(Schedulers.io()).doOnSubscribe {
@@ -124,11 +124,13 @@ class SharedCameraViewModel @Inject constructor() : ViewModel() {
disposables.add(
MediaFileHandler.getLastVaultFileFromDb().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe({ vaultFiles -> if (!vaultFiles.isNullOrEmpty()) {
- _lastMediaFileSuccess.postValue(vaultFiles[0])
- } else {
- _lastMediaFileError.postValue(Throwable("No media files found"))
- } },
+ .subscribe({ vaultFiles ->
+ if (!vaultFiles.isNullOrEmpty()) {
+ _lastMediaFileSuccess.postValue(vaultFiles[0])
+ } else {
+ _lastMediaFileError.postValue(Throwable("No media files found"))
+ }
+ },
{ throwable -> _lastMediaFileError.postValue(throwable) })
)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index b71cc5d94..c0bcdeec8 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -8,15 +8,16 @@ import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
-import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.FileTransferViewModel
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
+import timber.log.Timber
import javax.inject.Inject
@AndroidEntryPoint
class RecipientUploadFilesFragment :
BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
- private val viewModel: FileTransferViewModel by activityViewModels()
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
@Inject
lateinit var p2PSharedState: P2PSharedState
@@ -45,6 +46,9 @@ class RecipientUploadFilesFragment :
}
private fun observeUploadProgress() {
+ viewModel.uploadProgress.observe(viewLifecycleOwner) { state ->
+ Timber.d("State "+ state?.percent + " Status: "+state?.sessionStatus?.name)
+ }
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
index 3f8911e89..efa933f27 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientVerificationFragment.kt
@@ -41,7 +41,6 @@ class RecipientVerificationFragment :
toolbar.backClickListener = { navigateBackAndStopServer() }
discardBtn.setOnClickListener { navigateBackAndStopServer() }
- // Button is disabled until a request is received.
confirmAndConnectBtn.setOnClickListener(null)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
index b4fe0b659..51fc7c808 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
@@ -101,7 +101,6 @@ class FileTransferViewModel @Inject constructor(
}
}
-
fun uploadAllFiles() {
viewModelScope.launch {
val session = p2PSharedState.session ?: return@launch
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index 3c9fe6dff..6dd974176 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -23,6 +23,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
import javax.inject.Inject
@@ -52,6 +53,8 @@ class PeerToPeerViewModel @Inject constructor(
val incomingRequest: StateFlow = _incomingRequest
private val networkInfoManager = NetworkInfoManager(context)
val networkInfo: LiveData get() = networkInfoManager.networkInfo
+ private val _uploadProgress = SingleLiveEvent()
+ val uploadProgress: SingleLiveEvent = _uploadProgress
init {
viewModelScope.launch {
@@ -71,12 +74,17 @@ class PeerToPeerViewModel @Inject constructor(
_incomingRequest.value = IncomingRegistration(registrationId, payload)
if (!p2PState.isUsingManualConnection) {
- // QR-mode: auto-accept immediately
PeerEventManager.confirmRegistration(registrationId, true)
_registrationSuccess.postValue(true)
}
}
}
+
+ viewModelScope.launch {
+ PeerEventManager.uploadProgressStateFlow.collect { state ->
+
+ }
+ }
}
fun resetRegistrationState() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt
index 6616a8439..b2f3c2517 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt
@@ -57,7 +57,6 @@ class AttachmentsViewModel @Inject constructor(
val duplicateNameError: LiveData = _duplicateNameError
val counterData = MutableLiveData()
- //TODO AHLEM FIX THIS val counterData: LiveData = _counterData
private val _progressPercent = MutableLiveData>()
val progressPercent: LiveData> = _progressPercent
private val _mediaImportedWithDelete = MutableLiveData()
@@ -222,8 +221,7 @@ class AttachmentsViewModel @Inject constructor(
fun importVaultFiles(uris: List, parentId: String?, deleteOriginal: Boolean) {
if (uris.isEmpty()) return
- // counterData.value = 0
- // var counter = 1
+
var currentUri: Uri? = null
disposables.add(Flowable.fromIterable(uris).flatMap { uri ->
MediaFileHandler.importVaultFileUri(getApplication(), uri, parentId).toFlowable()
From 49891c92087069985fd7a4108b0d0430fcd08bc0 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 15 Jul 2025 17:49:10 +0100
Subject: [PATCH 075/153] WIP sending problem
---
.../mobile/data/peertopeer/TellaPeerToPeerClient.kt | 3 ++-
.../mobile/data/peertopeer/TellaPeerToPeerServer.kt | 13 +++++++------
.../mobile/domain/peertopeer/UploadProgressEvent.kt | 7 +++++++
.../peertopeer/viewmodel/FileTransferViewModel.kt | 7 ++++++-
.../peertopeer/viewmodel/PeerToPeerViewModel.kt | 1 +
.../viewmodel/state/UploadProgressState.kt | 10 ++++++++++
6 files changed, 33 insertions(+), 8 deletions(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/UploadProgressEvent.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index 6077e7a8e..f37890552 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -187,7 +187,6 @@ class TellaPeerToPeerClient @Inject constructor(){
}
}
-
suspend fun uploadFileWithProgress(
ip: String,
port: String,
@@ -199,6 +198,8 @@ class TellaPeerToPeerClient @Inject constructor(){
fileSize: Long,
onProgress: (bytesWritten: Long, totalBytes: Long) -> Unit
): Boolean = withContext(Dispatchers.IO) {
+
+ Timber.d("session id from the client+$sessionId")
val url = PeerApiRoutes.buildUploadUrl(ip, port, sessionId, fileId, transmissionId)
val client = getClientWithFingerprintValidation(expectedFingerprint)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 4c7f089d6..e6c19779e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -35,6 +35,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.domain.peertopeer.PeerResponse
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
+import timber.log.Timber
import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
@@ -118,6 +119,7 @@ class TellaPeerToPeerServer(
val sessionId = UUID.randomUUID().toString()
val session = PeerResponse(sessionId)
+ p2PSharedState.session?.sessionId = sessionId
serverSession = session
val accepted = try {
@@ -161,11 +163,7 @@ class TellaPeerToPeerServer(
val accepted = PeerEventManager.emitPrepareUploadRequest(request)
if (accepted) {
- val sessionId = serverSession?.sessionId ?: run {
- call.respond(HttpStatusCode.InternalServerError, "Missing session")
- return@post
- }
- p2PSharedState.session?.sessionId = sessionId
+
val session = P2PSession(title = request.title)
val responseFiles = request.files.map { file ->
@@ -196,12 +194,15 @@ class TellaPeerToPeerServer(
val fileId = call.parameters["fileId"]
val transmissionId = call.parameters["transmissionId"]
+ Timber.d("session id from the server +$sessionId")
+
if (sessionId == null || fileId == null || transmissionId == null) {
call.respond(HttpStatusCode.BadRequest, "Missing path parameters")
return@post
}
- if (sessionId != serverSession?.sessionId || sessionId != p2PSharedState.session?.sessionId) {
+ if (sessionId != p2PSharedState.session?.sessionId) {
+ Timber.d("session Id")
call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
return@post
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/UploadProgressEvent.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/UploadProgressEvent.kt
new file mode 100644
index 000000000..15d888c50
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/UploadProgressEvent.kt
@@ -0,0 +1,7 @@
+package org.horizontal.tella.mobile.domain.peertopeer
+
+data class UploadProgressEvent(
+ val fileId: String,
+ val bytesWritten: Long,
+ val totalBytes: Long
+)
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
index 51fc7c808..d5a99101e 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
@@ -1,5 +1,6 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel
+import android.annotation.SuppressLint
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
@@ -61,6 +62,7 @@ class FileTransferViewModel @Inject constructor(
}
fun prepareUploadsFromVaultFiles() {
+ Timber.d("session id ***prepareUploadsFromVaultFiles ${p2PSharedState.session?.sessionId}")
viewModelScope.launch {
when (val result = peerClient.prepareUpload(
@@ -97,6 +99,8 @@ class FileTransferViewModel @Inject constructor(
is PrepareUploadResult.Failure -> {
Timber.e(result.exception, "Unhandled error during upload")
}
+
+ else -> {}
}
}
}
@@ -119,11 +123,12 @@ class FileTransferViewModel @Inject constructor(
try {
if (inputStream != null) {
+ Timber.d("session id ***uploadAllFiles ${getSessionId()}")
peerClient.uploadFileWithProgress(
ip = ip,
port = port,
expectedFingerprint = fingerprint,
- sessionId = session.sessionId,
+ sessionId = getSessionId(),
fileId = progressFile.file.id,
transmissionId = progressFile.transmissionId.orEmpty(),
inputStream = inputStream,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index 6dd974176..c572fe5d9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -113,6 +113,7 @@ class PeerToPeerViewModel @Inject constructor(
with(p2PState) {
this.session?.sessionId = result.sessionId
}
+ Timber.d("session id ***startRegistration ${p2PState.session?.sessionId}")
_registrationSuccess.postValue(true)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt
new file mode 100644
index 000000000..e8ca736e4
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt
@@ -0,0 +1,10 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state
+
+import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
+import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
+
+data class UploadProgressState(
+ val percent: Int,
+ val sessionStatus: SessionStatus,
+ val files: List
+)
\ No newline at end of file
From 3c352531351b8a6b3f6887bdd9c79c1a5d41ae1e Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 15 Jul 2025 18:57:13 +0100
Subject: [PATCH 076/153] change post to put
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 2 +-
.../data/peertopeer/TellaPeerToPeerServer.kt | 17 ++++++++++-------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index f37890552..f67f64e67 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -208,7 +208,7 @@ class TellaPeerToPeerClient @Inject constructor(){
val request = Request.Builder()
.url(url)
- .post(requestBody)
+ .put(requestBody)
.addHeader(CONTENT_TYPE, CONTENT_TYPE_OCTET)
.build()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index e6c19779e..580a651d3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -16,6 +16,7 @@ import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.post
+import io.ktor.server.routing.put
import io.ktor.server.routing.routing
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -189,7 +190,7 @@ class TellaPeerToPeerServer(
}
}
- post(PeerApiRoutes.UPLOAD) {
+ put(PeerApiRoutes.UPLOAD) {
val sessionId = call.parameters["sessionId"]
val fileId = call.parameters["fileId"]
val transmissionId = call.parameters["transmissionId"]
@@ -198,13 +199,13 @@ class TellaPeerToPeerServer(
if (sessionId == null || fileId == null || transmissionId == null) {
call.respond(HttpStatusCode.BadRequest, "Missing path parameters")
- return@post
+ return@put
}
if (sessionId != p2PSharedState.session?.sessionId) {
Timber.d("session Id")
call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
- return@post
+ return@put
}
val session = p2PSharedState.session
@@ -212,7 +213,7 @@ class TellaPeerToPeerServer(
if (progressFile == null || progressFile.file.id != fileId) {
call.respond(HttpStatusCode.NotFound, "File not found in session")
- return@post
+ return@put
}
val tmpFile = createTempFile(prefix = "p2p_", suffix = "_$fileId")
@@ -220,7 +221,6 @@ class TellaPeerToPeerServer(
try {
val input = call.receiveStream().buffered()
- val totalBytesExpected = progressFile.file.size
var bytesRead = 0L
val buffer = ByteArray(8192)
@@ -232,7 +232,7 @@ class TellaPeerToPeerServer(
progressFile.bytesTransferred = bytesRead.toInt()
PeerEventManager.onUploadProgressState(
- p2PSharedState
+ p2PSharedState
)
}
@@ -243,7 +243,10 @@ class TellaPeerToPeerServer(
call.respond(HttpStatusCode.OK, "Upload complete")
} catch (e: Exception) {
progressFile.status = P2PFileStatus.FAILED
- call.respond(HttpStatusCode.InternalServerError, "Upload failed: ${e.message}")
+ call.respond(
+ HttpStatusCode.InternalServerError,
+ "Upload failed: ${e.message}"
+ )
} finally {
output.close()
}
From ae84efc85255592d7fc72c52447161069169f6a4 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Tue, 15 Jul 2025 19:59:26 +0100
Subject: [PATCH 077/153] Fix client upload code
---
.../mobile/data/peertopeer/TellaPeerToPeerClient.kt | 2 +-
.../mobile/data/peertopeer/TellaPeerToPeerServer.kt | 11 ++++++-----
.../peertopeer/viewmodel/FileTransferViewModel.kt | 9 +++------
3 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index f67f64e67..f37890552 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -208,7 +208,7 @@ class TellaPeerToPeerClient @Inject constructor(){
val request = Request.Builder()
.url(url)
- .put(requestBody)
+ .post(requestBody)
.addHeader(CONTENT_TYPE, CONTENT_TYPE_OCTET)
.build()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 580a651d3..caaaccbb5 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -165,7 +165,8 @@ class TellaPeerToPeerServer(
val accepted = PeerEventManager.emitPrepareUploadRequest(request)
if (accepted) {
- val session = P2PSession(title = request.title)
+ val session =
+ P2PSession(title = request.title, sessionId = request.sessionId)
val responseFiles = request.files.map { file ->
val transmissionId = UUID.randomUUID().toString()
@@ -190,7 +191,7 @@ class TellaPeerToPeerServer(
}
}
- put(PeerApiRoutes.UPLOAD) {
+ post(PeerApiRoutes.UPLOAD) {
val sessionId = call.parameters["sessionId"]
val fileId = call.parameters["fileId"]
val transmissionId = call.parameters["transmissionId"]
@@ -199,13 +200,13 @@ class TellaPeerToPeerServer(
if (sessionId == null || fileId == null || transmissionId == null) {
call.respond(HttpStatusCode.BadRequest, "Missing path parameters")
- return@put
+ return@post
}
if (sessionId != p2PSharedState.session?.sessionId) {
Timber.d("session Id")
call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
- return@put
+ return@post
}
val session = p2PSharedState.session
@@ -213,7 +214,7 @@ class TellaPeerToPeerServer(
if (progressFile == null || progressFile.file.id != fileId) {
call.respond(HttpStatusCode.NotFound, "File not found in session")
- return@put
+ return@post
}
val tmpFile = createTempFile(prefix = "p2p_", suffix = "_$fileId")
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
index d5a99101e..4c04183b9 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
@@ -26,7 +26,6 @@ import org.horizontal.tella.mobile.util.fromJsonToObjectList
import timber.log.Timber
import javax.inject.Inject
-
@HiltViewModel
class FileTransferViewModel @Inject constructor(
private val peerClient: TellaPeerToPeerClient,
@@ -100,7 +99,6 @@ class FileTransferViewModel @Inject constructor(
Timber.e(result.exception, "Unhandled error during upload")
}
- else -> {}
}
}
}
@@ -120,7 +118,7 @@ class FileTransferViewModel @Inject constructor(
MediaFileHandler.getStream(vaultFile)
progressFile.status = P2PFileStatus.SENDING
-
+ var percent = 0
try {
if (inputStream != null) {
Timber.d("session id ***uploadAllFiles ${getSessionId()}")
@@ -137,12 +135,11 @@ class FileTransferViewModel @Inject constructor(
progressFile.bytesTransferred = written.toInt()
val uploaded = session.files.values.sumOf { it.bytesTransferred }
- val percent =
+ percent =
if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
- _uploadProgress.postValue(percent)
}
}
-
+ _uploadProgress.postValue(percent)
progressFile.status = P2PFileStatus.FINISHED
} catch (e: Exception) {
progressFile.status = P2PFileStatus.FAILED
From 1a94fab0dbbab8f32a3642d3d964c842c7789e8c Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 16 Jul 2025 09:58:26 +0100
Subject: [PATCH 078/153] wip errors in registration
---
.../senderflow/ScanQrCodeFragment.kt | 26 +++++++++++++++++++
.../SenderManualConnectionFragment.kt | 13 +++++++---
2 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
index 19b98806f..81972b300 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/ScanQrCodeFragment.kt
@@ -12,10 +12,13 @@ import com.google.gson.Gson
import com.journeyapps.barcodescanner.BarcodeCallback
import com.journeyapps.barcodescanner.BarcodeResult
import com.journeyapps.barcodescanner.CompoundBarcodeView
+import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.domain.peertopeer.PeerConnectionPayload
import org.horizontal.tella.mobile.databinding.ScanQrcodeFragmentBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
+import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils.showStandardSheet
+import org.hzontal.shared_ui.utils.DialogUtils
class ScanQrCodeFragment :
BaseBindingFragment(ScanQrcodeFragmentBinding::inflate) {
@@ -74,6 +77,7 @@ class ScanQrCodeFragment :
} catch (e: Exception) {
e.printStackTrace()
+ DialogUtils.showBottomMessage(baseActivity, "Invalid QR Code", true)
// Show a message: Invalid QR Code
}
}
@@ -128,6 +132,28 @@ class ScanQrCodeFragment :
} else {
// handle error UI
}
+
+ viewModel.bottomMessageError.observe(viewLifecycleOwner) { message ->
+ DialogUtils.showBottomMessage(baseActivity, message, true)
+ }
+
+ viewModel.bottomSheetError.observe(viewLifecycleOwner) { (title, description) ->
+ showStandardSheet(
+ baseActivity.supportFragmentManager,
+ title,
+ description,
+ null,
+ getString(R.string.try_again),
+ null,
+ {
+ viewModel.startRegistration(
+ ip = viewModel.p2PState.ip,
+ port = viewModel.p2PState.port,
+ hash = viewModel.p2PState.hash,
+ pin = viewModel.p2PState.pin.toString()
+ )
+ })
+ }
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
index b779be8f9..dc9b5d9c1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderManualConnectionFragment.kt
@@ -71,10 +71,15 @@ class SenderManualConnectionFragment :
description,
null,
getString(R.string.try_again),
- null
- ) {
- activity?.onBackPressed()
- }
+ null,
+ {
+ viewModel.startRegistration(
+ ip = viewModel.p2PState.ip,
+ port = viewModel.p2PState.port,
+ hash = viewModel.p2PState.hash,
+ pin = viewModel.p2PState.pin.toString()
+ )
+ })
}
}
From abee08ea4a1d185d2e067b2313a18ee1d9b99a60 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 16 Jul 2025 10:42:30 +0100
Subject: [PATCH 079/153] Fix regression
---
.../fragment/peertopeer/senderflow/WaitingSenderFragment.kt | 2 +-
mobile/src/main/res/navigation/peer_to_peer_graph.xml | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
index b0c6bc408..6c1d87d5b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/WaitingSenderFragment.kt
@@ -42,8 +42,8 @@ class WaitingSenderFragment :
viewModel.p2PSharedState.session?.files?.let { filesMap ->
filesMap[fileInfo.id]?.transmissionId = fileInfo.transmissionId
}
- navManager().navigateFromWaitingSenderFragmentToUploadFilesFragment()
}
+ navManager().navigateFromWaitingSenderFragmentToUploadFilesFragment()
}
}
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index 75c5e882e..c16a8bc82 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -136,6 +136,7 @@
android:id="@+id/action_recipientSuccessFragment_to_recipientUploadFilesFragment"
app:destination="@id/recipientUploadFilesFragment" />
+
+ app:destination="@id/uploadSenderFragment" />
From 812ec135fa6cfde0efc70f4c3ff745f7d47e6fe0 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 16 Jul 2025 11:41:40 +0100
Subject: [PATCH 080/153] sender progress flow
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 1 -
.../senderflow/SenderUploadFilesFragment.kt | 10 ++---
.../viewmodel/FileTransferViewModel.kt | 43 +++++++++++++++----
3 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index caaaccbb5..9b8548b38 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -16,7 +16,6 @@ import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.post
-import io.ktor.server.routing.put
import io.ktor.server.routing.routing
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index d6740ff10..2dce9107d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -17,9 +17,9 @@ class SenderUploadFilesFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+ viewModel.uploadAllFiles()
showFormEndView()
observeUploadProgress()
- viewModel.uploadAllFiles()
}
private fun showFormEndView() {
@@ -36,10 +36,10 @@ class SenderUploadFilesFragment :
}
private fun observeUploadProgress() {
- viewModel.uploadProgress.observe(viewLifecycleOwner) { percent ->
- viewModel.p2PSharedState.session?.let { session ->
- endView.setUploadProgress(session.files.values.toList(), percent.toFloat())
- }
+ viewModel.uploadProgress.observe(viewLifecycleOwner) { state ->
+ val files = state.files
+ val percentFloat = state.percent / 100f
+ endView.setUploadProgress(files, percentFloat)
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
index 4c04183b9..b3b4b9059 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
@@ -23,6 +23,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.Event
import org.horizontal.tella.mobile.util.fromJsonToObjectList
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
import javax.inject.Inject
@@ -35,8 +36,8 @@ class FileTransferViewModel @Inject constructor(
val prepareResults: LiveData = _prepareResults
private val _prepareRejected = MutableLiveData>()
val prepareRejected: LiveData> = _prepareRejected
- private val _uploadProgress = MutableLiveData() // value from 0 to 100
- val uploadProgress: LiveData get() = _uploadProgress
+ private val _uploadProgress = MutableLiveData()
+ val uploadProgress: LiveData get() = _uploadProgress
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
@@ -114,11 +115,10 @@ class FileTransferViewModel @Inject constructor(
session.files.values.forEach { progressFile ->
val vaultFile = progressFile.vaultFile ?: return@forEach
- val inputStream =
- MediaFileHandler.getStream(vaultFile)
+ val inputStream = MediaFileHandler.getStream(vaultFile)
progressFile.status = P2PFileStatus.SENDING
- var percent = 0
+
try {
if (inputStream != null) {
Timber.d("session id ***uploadAllFiles ${getSessionId()}")
@@ -135,11 +135,18 @@ class FileTransferViewModel @Inject constructor(
progressFile.bytesTransferred = written.toInt()
val uploaded = session.files.values.sumOf { it.bytesTransferred }
- percent =
- if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
+ val percent = if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
+
+ _uploadProgress.postValue(
+ UploadProgressState(
+ percent = percent,
+ sessionStatus = session.status,
+ files = session.files.values.toList()
+ )
+ )
}
}
- _uploadProgress.postValue(percent)
+
progressFile.status = P2PFileStatus.FINISHED
} catch (e: Exception) {
progressFile.status = P2PFileStatus.FAILED
@@ -147,9 +154,29 @@ class FileTransferViewModel @Inject constructor(
} finally {
inputStream?.close()
}
+
+ // Post state after each file is done
+ _uploadProgress.postValue(
+ UploadProgressState(
+ percent = session.files.values.sumOf { it.bytesTransferred }.let {
+ if (totalSize > 0) ((it * 100) / totalSize).toInt() else 0
+ },
+ sessionStatus = session.status,
+ files = session.files.values.toList()
+ )
+ )
}
session.status = SessionStatus.FINISHED
+
+ // Final update after all uploads complete
+ _uploadProgress.postValue(
+ UploadProgressState(
+ percent = 100,
+ sessionStatus = session.status,
+ files = session.files.values.toList()
+ )
+ )
}
}
From 1dff4f3756d56ae02ddf071614ca7b5d89253fa1 Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 16 Jul 2025 12:48:28 +0100
Subject: [PATCH 081/153] wip cancel button
---
.../mobile/views/activity/MainActivity.kt | 7 +++++++
.../receipentflow/PeerToPeerFlags.kt | 8 ++++++++
.../RecipientUploadFilesFragment.kt | 18 ++++++++++++++++++
.../senderflow/SenderUploadFilesFragment.kt | 14 ++++++++++++++
.../main/res/layout/fragment_upload_files.xml | 1 -
mobile/src/main/res/values-ar/strings.xml | 2 ++
mobile/src/main/res/values-be/strings.xml | 2 ++
mobile/src/main/res/values-blk/strings.xml | 2 ++
mobile/src/main/res/values-bn/strings.xml | 2 ++
mobile/src/main/res/values-es-rCU/strings.xml | 2 ++
mobile/src/main/res/values-es/strings.xml | 2 ++
mobile/src/main/res/values-fa-rIR/strings.xml | 2 ++
mobile/src/main/res/values-fr/strings.xml | 2 ++
mobile/src/main/res/values-hdpi/strings.xml | 2 ++
mobile/src/main/res/values-in/strings.xml | 2 ++
mobile/src/main/res/values-kac/strings.xml | 2 ++
mobile/src/main/res/values-kn/strings.xml | 2 ++
mobile/src/main/res/values-ksw/strings.xml | 2 ++
mobile/src/main/res/values-ku/strings.xml | 2 ++
mobile/src/main/res/values-mdpi/strings.xml | 2 ++
mobile/src/main/res/values-ml/strings.xml | 2 ++
mobile/src/main/res/values-my/strings.xml | 2 ++
mobile/src/main/res/values-ndc/strings.xml | 2 ++
mobile/src/main/res/values-pt-rMZ/strings.xml | 2 ++
mobile/src/main/res/values-pt/strings.xml | 2 ++
mobile/src/main/res/values-ru/strings.xml | 2 ++
mobile/src/main/res/values-sn-rZW/strings.xml | 2 ++
mobile/src/main/res/values-sw600dp/strings.xml | 2 ++
mobile/src/main/res/values-ta/strings.xml | 2 ++
mobile/src/main/res/values-tr/strings.xml | 2 ++
mobile/src/main/res/values-ts/strings.xml | 2 ++
mobile/src/main/res/values-v21/strings.xml | 2 ++
mobile/src/main/res/values-v26/strings.xml | 2 ++
mobile/src/main/res/values-vi/strings.xml | 2 ++
mobile/src/main/res/values-w820dp/strings.xml | 2 ++
mobile/src/main/res/values-xhdpi/strings.xml | 2 ++
mobile/src/main/res/values-xxhdpi/strings.xml | 2 ++
mobile/src/main/res/values/strings.xml | 3 +++
38 files changed, 114 insertions(+), 1 deletion(-)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/PeerToPeerFlags.kt
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/MainActivity.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/MainActivity.kt
index 9e2bb2281..ec05290ac 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/MainActivity.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/activity/MainActivity.kt
@@ -40,6 +40,7 @@ import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BaseRepor
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BaseReportsEntryFragment
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.BaseReportsSendFragment
import org.horizontal.tella.mobile.views.fragment.main_connexions.base.MainReportFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow.PeerToPeerFlags
import org.horizontal.tella.mobile.views.fragment.recorder.MicFragment
import org.horizontal.tella.mobile.views.fragment.reports.send.ReportsSendFragment
import org.horizontal.tella.mobile.views.fragment.uwazi.SubmittedPreviewFragment
@@ -54,6 +55,7 @@ import org.horizontal.tella.mobile.views.fragment.vault.home.VAULT_FILTER
import org.horizontal.tella.mobile.views.interfaces.IMainNavigationInterface
import org.horizontal.tella.mobile.views.interfaces.VerificationWorkStatusCallback
import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils
+import org.hzontal.shared_ui.utils.DialogUtils
import permissions.dispatcher.NeedsPermission
import timber.log.Timber
@@ -239,6 +241,7 @@ class MainActivity : MetadataActivity(), IMetadataAttachPresenterContract.IView,
supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
it.onActivityResult(requestCode, resultCode, data)
}
+
}
private fun isLocationSettingsRequestCode(requestCode: Int): Boolean {
@@ -354,6 +357,10 @@ class MainActivity : MetadataActivity(), IMetadataAttachPresenterContract.IView,
super.onResume()
startLocationMetadataListening()
mOrientationEventListener!!.enable()
+ if (PeerToPeerFlags.cancelled) {
+ PeerToPeerFlags.cancelled = false
+ DialogUtils.showBottomMessage(this, "Nearby sharing was cancelled.", false)
+ }
}
override fun onPause() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/PeerToPeerFlags.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/PeerToPeerFlags.kt
new file mode 100644
index 000000000..3f95c004b
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/PeerToPeerFlags.kt
@@ -0,0 +1,8 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+
+/**
+ * Created by wafa on 16/7/2025.
+ */
+object PeerToPeerFlags {
+ var cancelled = false
+}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index c0bcdeec8..061f15690 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -1,15 +1,20 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
+import android.app.Activity
+import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.MyApplication
+import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
+import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils.showStandardSheet
+import org.hzontal.shared_ui.utils.DialogUtils
import timber.log.Timber
import javax.inject.Inject
@@ -28,6 +33,19 @@ class RecipientUploadFilesFragment :
super.onViewCreated(view, savedInstanceState)
showFormEndView()
observeUploadProgress()
+ binding.cancel.setOnClickListener {
+ showStandardSheet(
+ baseActivity.supportFragmentManager,
+ getString(R.string.stop_sharing_files),
+ getString(R.string.nearby_sharing_will_be_stopped_the_recipient_will_not_have_access_to_files_that_were_not_fully_transferred),
+ getString(R.string.action_continue).uppercase(),
+ getString(R.string.stop).uppercase(),
+ {},
+ {
+ PeerToPeerFlags.cancelled = true
+ baseActivity.finish()
+ })
+ }
}
private fun showFormEndView() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index 2dce9107d..37a30da26 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -4,10 +4,12 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
import org.horizontal.tella.mobile.MyApplication
+import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.FileTransferViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
+import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils.showStandardSheet
class SenderUploadFilesFragment :
BaseBindingFragment(FragmentUploadFilesBinding::inflate) {
@@ -20,6 +22,17 @@ class SenderUploadFilesFragment :
viewModel.uploadAllFiles()
showFormEndView()
observeUploadProgress()
+ viewModel.uploadAllFiles()
+ binding.cancel.setOnClickListener {
+ showStandardSheet(
+ baseActivity.supportFragmentManager,
+ getString(R.string.stop_sharing_files),
+ getString(R.string.nearby_sharing_will_be_stopped_the_recipient_will_not_have_access_to_files_that_were_not_fully_transferred),
+ getString(R.string.action_continue).uppercase(),
+ getString(R.string.stop).uppercase(),
+ {},
+ {})
+ }
}
private fun showFormEndView() {
@@ -29,6 +42,7 @@ class SenderUploadFilesFragment :
endView = PeerToPeerEndView(
baseActivity, session.title ?: "Transfer"
)
+
endView.setFiles(files, MyApplication.isConnectedToInternet(baseActivity), false)
binding.endViewContainer.removeAllViews()
binding.endViewContainer.addView(endView)
diff --git a/mobile/src/main/res/layout/fragment_upload_files.xml b/mobile/src/main/res/layout/fragment_upload_files.xml
index e19255272..b56564957 100644
--- a/mobile/src/main/res/layout/fragment_upload_files.xml
+++ b/mobile/src/main/res/layout/fragment_upload_files.xml
@@ -47,7 +47,6 @@
android:layout_marginStart="@dimen/activity_horizontal_large_margin"
android:layout_marginEnd="@dimen/activity_horizontal_large_margin"
android:layout_marginBottom="18dp"
-
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
diff --git a/mobile/src/main/res/values-ar/strings.xml b/mobile/src/main/res/values-ar/strings.xml
index 26aba9d01..51d078583 100644
--- a/mobile/src/main/res/values-ar/strings.xml
+++ b/mobile/src/main/res/values-ar/strings.xml
@@ -1005,4 +1005,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-be/strings.xml b/mobile/src/main/res/values-be/strings.xml
index 02908261b..a29016ccf 100644
--- a/mobile/src/main/res/values-be/strings.xml
+++ b/mobile/src/main/res/values-be/strings.xml
@@ -1006,4 +1006,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-blk/strings.xml b/mobile/src/main/res/values-blk/strings.xml
index 5ea8e3ff1..543cc4958 100644
--- a/mobile/src/main/res/values-blk/strings.xml
+++ b/mobile/src/main/res/values-blk/strings.xml
@@ -144,4 +144,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-bn/strings.xml b/mobile/src/main/res/values-bn/strings.xml
index 25ee1f8f2..082fe71cb 100644
--- a/mobile/src/main/res/values-bn/strings.xml
+++ b/mobile/src/main/res/values-bn/strings.xml
@@ -986,4 +986,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-es-rCU/strings.xml b/mobile/src/main/res/values-es-rCU/strings.xml
index 77c3e374f..8b9be4278 100644
--- a/mobile/src/main/res/values-es-rCU/strings.xml
+++ b/mobile/src/main/res/values-es-rCU/strings.xml
@@ -1007,4 +1007,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-es/strings.xml b/mobile/src/main/res/values-es/strings.xml
index 7fe505fa4..a36797464 100644
--- a/mobile/src/main/res/values-es/strings.xml
+++ b/mobile/src/main/res/values-es/strings.xml
@@ -990,4 +990,6 @@ Este feedback es anónimo, así que asegúrate de incluir tu información de con
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-fa-rIR/strings.xml b/mobile/src/main/res/values-fa-rIR/strings.xml
index 68d5d66b6..2b216405c 100644
--- a/mobile/src/main/res/values-fa-rIR/strings.xml
+++ b/mobile/src/main/res/values-fa-rIR/strings.xml
@@ -1003,4 +1003,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-fr/strings.xml b/mobile/src/main/res/values-fr/strings.xml
index 7dbf91262..cf88263d2 100644
--- a/mobile/src/main/res/values-fr/strings.xml
+++ b/mobile/src/main/res/values-fr/strings.xml
@@ -1000,4 +1000,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-hdpi/strings.xml b/mobile/src/main/res/values-hdpi/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-hdpi/strings.xml
+++ b/mobile/src/main/res/values-hdpi/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values-in/strings.xml b/mobile/src/main/res/values-in/strings.xml
index e64827853..d16fb5eb7 100644
--- a/mobile/src/main/res/values-in/strings.xml
+++ b/mobile/src/main/res/values-in/strings.xml
@@ -988,4 +988,6 @@ Apakah Anda ingin membagikan analitik kepada tim Tella?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-kac/strings.xml b/mobile/src/main/res/values-kac/strings.xml
index 6e755dcd0..52b875932 100644
--- a/mobile/src/main/res/values-kac/strings.xml
+++ b/mobile/src/main/res/values-kac/strings.xml
@@ -1006,4 +1006,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-kn/strings.xml b/mobile/src/main/res/values-kn/strings.xml
index 6681f7b22..7b4cf8afe 100644
--- a/mobile/src/main/res/values-kn/strings.xml
+++ b/mobile/src/main/res/values-kn/strings.xml
@@ -1006,4 +1006,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-ksw/strings.xml b/mobile/src/main/res/values-ksw/strings.xml
index ef08d50d1..4f70d9e9f 100644
--- a/mobile/src/main/res/values-ksw/strings.xml
+++ b/mobile/src/main/res/values-ksw/strings.xml
@@ -989,4 +989,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-ku/strings.xml b/mobile/src/main/res/values-ku/strings.xml
index 911593d8d..35317766c 100644
--- a/mobile/src/main/res/values-ku/strings.xml
+++ b/mobile/src/main/res/values-ku/strings.xml
@@ -1001,4 +1001,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-mdpi/strings.xml b/mobile/src/main/res/values-mdpi/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-mdpi/strings.xml
+++ b/mobile/src/main/res/values-mdpi/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ml/strings.xml b/mobile/src/main/res/values-ml/strings.xml
index 66403f6c3..6e60a7bca 100644
--- a/mobile/src/main/res/values-ml/strings.xml
+++ b/mobile/src/main/res/values-ml/strings.xml
@@ -1006,4 +1006,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-my/strings.xml b/mobile/src/main/res/values-my/strings.xml
index e23266056..7cbde78b5 100644
--- a/mobile/src/main/res/values-my/strings.xml
+++ b/mobile/src/main/res/values-my/strings.xml
@@ -989,4 +989,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-ndc/strings.xml b/mobile/src/main/res/values-ndc/strings.xml
index 826c63970..eb7c5fc73 100644
--- a/mobile/src/main/res/values-ndc/strings.xml
+++ b/mobile/src/main/res/values-ndc/strings.xml
@@ -980,4 +980,6 @@ Wainda kupaurirana maonere no chikwatha Tella?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-pt-rMZ/strings.xml b/mobile/src/main/res/values-pt-rMZ/strings.xml
index 4e8d3e6f3..4e7d1e583 100644
--- a/mobile/src/main/res/values-pt-rMZ/strings.xml
+++ b/mobile/src/main/res/values-pt-rMZ/strings.xml
@@ -992,4 +992,6 @@ Gostaria de partilhar dados com a equipa do Tella?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-pt/strings.xml b/mobile/src/main/res/values-pt/strings.xml
index cca390370..b67f8e7fd 100644
--- a/mobile/src/main/res/values-pt/strings.xml
+++ b/mobile/src/main/res/values-pt/strings.xml
@@ -1006,4 +1006,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-ru/strings.xml b/mobile/src/main/res/values-ru/strings.xml
index 6dbfa6f3e..f6ab51a34 100644
--- a/mobile/src/main/res/values-ru/strings.xml
+++ b/mobile/src/main/res/values-ru/strings.xml
@@ -1016,4 +1016,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-sn-rZW/strings.xml b/mobile/src/main/res/values-sn-rZW/strings.xml
index 826c63970..e28e5c649 100644
--- a/mobile/src/main/res/values-sn-rZW/strings.xml
+++ b/mobile/src/main/res/values-sn-rZW/strings.xml
@@ -980,4 +980,6 @@ Wainda kupaurirana maonere no chikwatha Tella?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-sw600dp/strings.xml b/mobile/src/main/res/values-sw600dp/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-sw600dp/strings.xml
+++ b/mobile/src/main/res/values-sw600dp/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ta/strings.xml b/mobile/src/main/res/values-ta/strings.xml
index 5e59a8067..4a2e8f99d 100644
--- a/mobile/src/main/res/values-ta/strings.xml
+++ b/mobile/src/main/res/values-ta/strings.xml
@@ -1006,4 +1006,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-tr/strings.xml b/mobile/src/main/res/values-tr/strings.xml
index 5a70fe746..51e2ad678 100644
--- a/mobile/src/main/res/values-tr/strings.xml
+++ b/mobile/src/main/res/values-tr/strings.xml
@@ -986,4 +986,6 @@ Tella ekibiyle analizleri paylaşmak ister misiniz?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-ts/strings.xml b/mobile/src/main/res/values-ts/strings.xml
index 357000ae3..073d774bc 100644
--- a/mobile/src/main/res/values-ts/strings.xml
+++ b/mobile/src/main/res/values-ts/strings.xml
@@ -976,4 +976,6 @@ yi fanele ku ku nyika vutshokotshoko bya servhidor.
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-v21/strings.xml b/mobile/src/main/res/values-v21/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-v21/strings.xml
+++ b/mobile/src/main/res/values-v21/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values-v26/strings.xml b/mobile/src/main/res/values-v26/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-v26/strings.xml
+++ b/mobile/src/main/res/values-v26/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values-vi/strings.xml b/mobile/src/main/res/values-vi/strings.xml
index 6bcd0bb37..e6754abfc 100644
--- a/mobile/src/main/res/values-vi/strings.xml
+++ b/mobile/src/main/res/values-vi/strings.xml
@@ -996,4 +996,6 @@ Would you like to share analytics with the Tella team?
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
diff --git a/mobile/src/main/res/values-w820dp/strings.xml b/mobile/src/main/res/values-w820dp/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-w820dp/strings.xml
+++ b/mobile/src/main/res/values-w820dp/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xhdpi/strings.xml b/mobile/src/main/res/values-xhdpi/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-xhdpi/strings.xml
+++ b/mobile/src/main/res/values-xhdpi/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xxhdpi/strings.xml b/mobile/src/main/res/values-xxhdpi/strings.xml
index 8f72f3128..807975024 100644
--- a/mobile/src/main/res/values-xxhdpi/strings.xml
+++ b/mobile/src/main/res/values-xxhdpi/strings.xml
@@ -3,4 +3,6 @@
Send files
Location permission is required to get WiFi SSID.
Failed to open location settings.
+ Stop sharing files?
+ stop
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index 55e34ebe5..32335cdd8 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1057,4 +1057,7 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Location permission is required to get WiFi SSID.
Failed to open location settings.
Try again
+ Stop sharing files?
+ Nearby sharing will be stopped. The recipient will not have access to files that were not fully transferred.
+ stop
From ae1235f6f6ff4e90da79ded87c8af3ed1bd0ad0f Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 16 Jul 2025 15:23:45 +0100
Subject: [PATCH 082/153] wip resultView
---
.../senderflow/PeerToPeerParticipant.kt | 9 ++
.../senderflow/PeerToPeerResultFragment.kt | 111 ++++++++++++++++++
.../layout/fragment_peer_to_peer_result.xml | 56 +++++++++
mobile/src/main/res/values-ar/strings.xml | 1 +
mobile/src/main/res/values-be/strings.xml | 1 +
mobile/src/main/res/values-blk/strings.xml | 1 +
mobile/src/main/res/values-bn/strings.xml | 1 +
mobile/src/main/res/values-es-rCU/strings.xml | 1 +
mobile/src/main/res/values-es/strings.xml | 1 +
mobile/src/main/res/values-fa-rIR/strings.xml | 1 +
mobile/src/main/res/values-fr/strings.xml | 1 +
mobile/src/main/res/values-hdpi/strings.xml | 1 +
mobile/src/main/res/values-in/strings.xml | 1 +
mobile/src/main/res/values-kac/strings.xml | 1 +
mobile/src/main/res/values-kn/strings.xml | 1 +
mobile/src/main/res/values-ksw/strings.xml | 1 +
mobile/src/main/res/values-ku/strings.xml | 1 +
mobile/src/main/res/values-mdpi/strings.xml | 1 +
mobile/src/main/res/values-ml/strings.xml | 1 +
mobile/src/main/res/values-my/strings.xml | 1 +
mobile/src/main/res/values-ndc/strings.xml | 1 +
mobile/src/main/res/values-pt-rMZ/strings.xml | 1 +
mobile/src/main/res/values-pt/strings.xml | 1 +
mobile/src/main/res/values-ru/strings.xml | 1 +
mobile/src/main/res/values-sn-rZW/strings.xml | 1 +
.../src/main/res/values-sw600dp/strings.xml | 1 +
mobile/src/main/res/values-ta/strings.xml | 1 +
mobile/src/main/res/values-tr/strings.xml | 1 +
mobile/src/main/res/values-ts/strings.xml | 1 +
mobile/src/main/res/values-v21/strings.xml | 1 +
mobile/src/main/res/values-v26/strings.xml | 1 +
mobile/src/main/res/values-vi/strings.xml | 1 +
mobile/src/main/res/values-w820dp/strings.xml | 1 +
mobile/src/main/res/values-xhdpi/strings.xml | 1 +
mobile/src/main/res/values-xxhdpi/strings.xml | 1 +
mobile/src/main/res/values/strings.xml | 15 +++
36 files changed, 223 insertions(+)
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerParticipant.kt
create mode 100644 mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
create mode 100644 mobile/src/main/res/layout/fragment_peer_to_peer_result.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerParticipant.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerParticipant.kt
new file mode 100644
index 000000000..18bbfdc23
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerParticipant.kt
@@ -0,0 +1,9 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
+
+/**
+ * Created by wafa on 16/7/2025.
+ */
+enum class PeerToPeerParticipant {
+ SENDER,
+ RECIPIENT
+}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
new file mode 100644
index 000000000..362a25158
--- /dev/null
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
@@ -0,0 +1,111 @@
+package org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow
+
+import android.graphics.PorterDuff
+import android.os.Bundle
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.activityViewModels
+import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
+import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
+import org.horizontal.tella.mobile.databinding.FragmentPeerToPeerResultBinding
+import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
+
+class PeerToPeerResultFragment :
+ BaseBindingFragment(FragmentPeerToPeerResultBinding::inflate) {
+
+ private val viewModel: PeerToPeerViewModel by activityViewModels()
+ private lateinit var participant: PeerToPeerParticipant
+ private var transferredFiles: List? = null
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ // Get values from shared state
+ participant = PeerToPeerParticipant.SENDER
+ transferredFiles = viewModel.p2PState.session.files.values.toList()
+
+ setupImage()
+ setupTexts()
+ setupButton()
+ }
+
+
+ private fun setupImage() {
+ binding.setupImgV.run {
+ val isSuccess = allFilesTransferred
+ setImageResource(if (isSuccess) R.drawable.checked_circle else R.drawable.ic_warning_orange)
+
+ if (!isSuccess) {
+ val whiteColor = ContextCompat.getColor(context, R.color.wa_white)
+ setColorFilter(whiteColor, PorterDuff.Mode.SRC_IN)
+ } else {
+ clearColorFilter()
+ }
+ }
+ }
+
+ private fun setupTexts() {
+ binding.tileTv.text = getString(if (allFilesTransferred) R.string.success_title else R.string.failure_title)
+ binding.descriptionTv.text = computeSubtitle()
+ }
+
+ private fun setupButton() {
+ if (!noFilesTransferred) {
+ binding.viewFilesBtn.apply {
+ setText(getString(R.string.view_files_action))
+ visibility = View.VISIBLE
+ setOnClickListener {
+ // TODO: Implement button action
+ }
+ }
+ } else {
+ binding.viewFilesBtn.visibility = View.GONE
+ }
+ }
+
+ private fun computeSubtitle(): String {
+ val total = transferredFiles?.size
+ val successCount = transferredFiles?.count { it.status == successStatus }
+ val failureCount = total?.minus(successCount!!)
+
+ return when {
+ successCount == total -> getString(if (total == 1) successSingleRes() else successMultipleRes(), total)
+ failureCount == total -> getString(if (total == 1) failureSingleRes() else failureMultipleRes(), total)
+ else -> {
+ val resId = when {
+ successCount == 1 && failureCount == 1 -> R.string.file_received_file_not_received
+ successCount == 1 -> R.string.file_received_files_not_received
+ failureCount == 1 -> R.string.files_received_file_not_received
+ else -> R.string.files_received_files_not_received
+ }
+ getString(resId, successCount, failureCount)
+ }
+ }
+ }
+
+ private val successStatus: P2PFileStatus
+ get() = P2PFileStatus.FINISHED
+
+ private val allFilesTransferred: Boolean
+ get() = transferredFiles?.all { it.status == successStatus } == true
+
+ private val noFilesTransferred: Boolean
+ get() = transferredFiles?.none { it.status == successStatus } == true
+
+ private fun successSingleRes(): Int =
+ if (participant == PeerToPeerParticipant.RECIPIENT)
+ R.string.success_file_received_expl
+ else
+ R.string.success_file_sent_expl
+
+ private fun successMultipleRes(): Int =
+ if (participant == PeerToPeerParticipant.RECIPIENT)
+ R.string.success_files_received_expl
+ else
+ R.string.success_files_sent_expl
+
+ private fun failureSingleRes(): Int = R.string.failure_file_received_expl
+ private fun failureMultipleRes(): Int = R.string.failure_files_received_expl
+}
\ No newline at end of file
diff --git a/mobile/src/main/res/layout/fragment_peer_to_peer_result.xml b/mobile/src/main/res/layout/fragment_peer_to_peer_result.xml
new file mode 100644
index 000000000..3cb86a22e
--- /dev/null
+++ b/mobile/src/main/res/layout/fragment_peer_to_peer_result.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ar/strings.xml b/mobile/src/main/res/values-ar/strings.xml
index 51d078583..93f33d150 100644
--- a/mobile/src/main/res/values-ar/strings.xml
+++ b/mobile/src/main/res/values-ar/strings.xml
@@ -1007,4 +1007,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-be/strings.xml b/mobile/src/main/res/values-be/strings.xml
index a29016ccf..518ba5415 100644
--- a/mobile/src/main/res/values-be/strings.xml
+++ b/mobile/src/main/res/values-be/strings.xml
@@ -1008,4 +1008,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-blk/strings.xml b/mobile/src/main/res/values-blk/strings.xml
index 543cc4958..2b61d7cbb 100644
--- a/mobile/src/main/res/values-blk/strings.xml
+++ b/mobile/src/main/res/values-blk/strings.xml
@@ -146,4 +146,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-bn/strings.xml b/mobile/src/main/res/values-bn/strings.xml
index 082fe71cb..bd0343d1f 100644
--- a/mobile/src/main/res/values-bn/strings.xml
+++ b/mobile/src/main/res/values-bn/strings.xml
@@ -988,4 +988,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-es-rCU/strings.xml b/mobile/src/main/res/values-es-rCU/strings.xml
index 8b9be4278..cd106a53b 100644
--- a/mobile/src/main/res/values-es-rCU/strings.xml
+++ b/mobile/src/main/res/values-es-rCU/strings.xml
@@ -1009,4 +1009,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-es/strings.xml b/mobile/src/main/res/values-es/strings.xml
index a36797464..cefdf9d3c 100644
--- a/mobile/src/main/res/values-es/strings.xml
+++ b/mobile/src/main/res/values-es/strings.xml
@@ -992,4 +992,5 @@ Este feedback es anónimo, así que asegúrate de incluir tu información de con
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-fa-rIR/strings.xml b/mobile/src/main/res/values-fa-rIR/strings.xml
index 2b216405c..007e9d94c 100644
--- a/mobile/src/main/res/values-fa-rIR/strings.xml
+++ b/mobile/src/main/res/values-fa-rIR/strings.xml
@@ -1005,4 +1005,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-fr/strings.xml b/mobile/src/main/res/values-fr/strings.xml
index cf88263d2..fd663c7ad 100644
--- a/mobile/src/main/res/values-fr/strings.xml
+++ b/mobile/src/main/res/values-fr/strings.xml
@@ -1002,4 +1002,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-hdpi/strings.xml b/mobile/src/main/res/values-hdpi/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-hdpi/strings.xml
+++ b/mobile/src/main/res/values-hdpi/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values-in/strings.xml b/mobile/src/main/res/values-in/strings.xml
index d16fb5eb7..118dc2fde 100644
--- a/mobile/src/main/res/values-in/strings.xml
+++ b/mobile/src/main/res/values-in/strings.xml
@@ -990,4 +990,5 @@ Apakah Anda ingin membagikan analitik kepada tim Tella?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-kac/strings.xml b/mobile/src/main/res/values-kac/strings.xml
index 52b875932..e815c91e3 100644
--- a/mobile/src/main/res/values-kac/strings.xml
+++ b/mobile/src/main/res/values-kac/strings.xml
@@ -1008,4 +1008,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-kn/strings.xml b/mobile/src/main/res/values-kn/strings.xml
index 7b4cf8afe..394aec790 100644
--- a/mobile/src/main/res/values-kn/strings.xml
+++ b/mobile/src/main/res/values-kn/strings.xml
@@ -1008,4 +1008,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-ksw/strings.xml b/mobile/src/main/res/values-ksw/strings.xml
index 4f70d9e9f..5e5da015c 100644
--- a/mobile/src/main/res/values-ksw/strings.xml
+++ b/mobile/src/main/res/values-ksw/strings.xml
@@ -991,4 +991,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-ku/strings.xml b/mobile/src/main/res/values-ku/strings.xml
index 35317766c..2ce58bf9e 100644
--- a/mobile/src/main/res/values-ku/strings.xml
+++ b/mobile/src/main/res/values-ku/strings.xml
@@ -1003,4 +1003,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-mdpi/strings.xml b/mobile/src/main/res/values-mdpi/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-mdpi/strings.xml
+++ b/mobile/src/main/res/values-mdpi/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ml/strings.xml b/mobile/src/main/res/values-ml/strings.xml
index 6e60a7bca..80b92b4a4 100644
--- a/mobile/src/main/res/values-ml/strings.xml
+++ b/mobile/src/main/res/values-ml/strings.xml
@@ -1008,4 +1008,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-my/strings.xml b/mobile/src/main/res/values-my/strings.xml
index 7cbde78b5..dfc48aaa0 100644
--- a/mobile/src/main/res/values-my/strings.xml
+++ b/mobile/src/main/res/values-my/strings.xml
@@ -991,4 +991,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-ndc/strings.xml b/mobile/src/main/res/values-ndc/strings.xml
index eb7c5fc73..4e11f421f 100644
--- a/mobile/src/main/res/values-ndc/strings.xml
+++ b/mobile/src/main/res/values-ndc/strings.xml
@@ -982,4 +982,5 @@ Wainda kupaurirana maonere no chikwatha Tella?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-pt-rMZ/strings.xml b/mobile/src/main/res/values-pt-rMZ/strings.xml
index 4e7d1e583..7afe2f38e 100644
--- a/mobile/src/main/res/values-pt-rMZ/strings.xml
+++ b/mobile/src/main/res/values-pt-rMZ/strings.xml
@@ -994,4 +994,5 @@ Gostaria de partilhar dados com a equipa do Tella?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-pt/strings.xml b/mobile/src/main/res/values-pt/strings.xml
index b67f8e7fd..27a723c2c 100644
--- a/mobile/src/main/res/values-pt/strings.xml
+++ b/mobile/src/main/res/values-pt/strings.xml
@@ -1008,4 +1008,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-ru/strings.xml b/mobile/src/main/res/values-ru/strings.xml
index f6ab51a34..c6b174590 100644
--- a/mobile/src/main/res/values-ru/strings.xml
+++ b/mobile/src/main/res/values-ru/strings.xml
@@ -1018,4 +1018,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-sn-rZW/strings.xml b/mobile/src/main/res/values-sn-rZW/strings.xml
index e28e5c649..33bcc3d08 100644
--- a/mobile/src/main/res/values-sn-rZW/strings.xml
+++ b/mobile/src/main/res/values-sn-rZW/strings.xml
@@ -982,4 +982,5 @@ Wainda kupaurirana maonere no chikwatha Tella?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-sw600dp/strings.xml b/mobile/src/main/res/values-sw600dp/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-sw600dp/strings.xml
+++ b/mobile/src/main/res/values-sw600dp/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values-ta/strings.xml b/mobile/src/main/res/values-ta/strings.xml
index 4a2e8f99d..5f1987688 100644
--- a/mobile/src/main/res/values-ta/strings.xml
+++ b/mobile/src/main/res/values-ta/strings.xml
@@ -1008,4 +1008,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-tr/strings.xml b/mobile/src/main/res/values-tr/strings.xml
index 51e2ad678..55637b0ff 100644
--- a/mobile/src/main/res/values-tr/strings.xml
+++ b/mobile/src/main/res/values-tr/strings.xml
@@ -988,4 +988,5 @@ Tella ekibiyle analizleri paylaşmak ister misiniz?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-ts/strings.xml b/mobile/src/main/res/values-ts/strings.xml
index 073d774bc..d6c91c436 100644
--- a/mobile/src/main/res/values-ts/strings.xml
+++ b/mobile/src/main/res/values-ts/strings.xml
@@ -978,4 +978,5 @@ yi fanele ku ku nyika vutshokotshoko bya servhidor.
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-v21/strings.xml b/mobile/src/main/res/values-v21/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-v21/strings.xml
+++ b/mobile/src/main/res/values-v21/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values-v26/strings.xml b/mobile/src/main/res/values-v26/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-v26/strings.xml
+++ b/mobile/src/main/res/values-v26/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values-vi/strings.xml b/mobile/src/main/res/values-vi/strings.xml
index e6754abfc..81fb3af01 100644
--- a/mobile/src/main/res/values-vi/strings.xml
+++ b/mobile/src/main/res/values-vi/strings.xml
@@ -998,4 +998,5 @@ Would you like to share analytics with the Tella team?
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
diff --git a/mobile/src/main/res/values-w820dp/strings.xml b/mobile/src/main/res/values-w820dp/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-w820dp/strings.xml
+++ b/mobile/src/main/res/values-w820dp/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xhdpi/strings.xml b/mobile/src/main/res/values-xhdpi/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-xhdpi/strings.xml
+++ b/mobile/src/main/res/values-xhdpi/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values-xxhdpi/strings.xml b/mobile/src/main/res/values-xxhdpi/strings.xml
index 807975024..dd1a6f2a8 100644
--- a/mobile/src/main/res/values-xxhdpi/strings.xml
+++ b/mobile/src/main/res/values-xxhdpi/strings.xml
@@ -5,4 +5,5 @@
Failed to open location settings.
Stop sharing files?
stop
+ VIEW FILES
\ No newline at end of file
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index 32335cdd8..da4d2c6ba 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1060,4 +1060,19 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Stop sharing files?
Nearby sharing will be stopped. The recipient will not have access to files that were not fully transferred.
stop
+ Success
+ Something went wrong
+ You have successfully received %d file.
+ You have successfully received %d files.
+ You have successfully sent %d file.
+ You have successfully sent %d files.
+ We couldn't receive %d file.
+ We couldn't receive %d files.
+ 1 file received, 1 file not received
+ 1 file received, %d files not received
+ %d files received, 1 file not received
+ %d files received, %d files not received
+ View Files
+ VIEW FILES
+
From 8a13fd4a5a3f132a3a52f93297f88475cc510c97 Mon Sep 17 00:00:00 2001
From: wafa
Date: Wed, 16 Jul 2025 16:38:56 +0100
Subject: [PATCH 083/153] wip recipient progress and result view
---
.../data/peertopeer/TellaPeerToPeerServer.kt | 60 +++++++++------
.../domain/peertopeer/PeerEventManager.kt | 22 +-----
.../RecipientUploadFilesFragment.kt | 20 +++--
.../senderflow/PeerToPeerResultFragment.kt | 57 +++++++-------
.../viewmodel/PeerToPeerViewModel.kt | 75 ++++++++++++++++++-
.../attachements/AttachmentsViewModel.kt | 3 -
mobile/src/main/res/values/strings.xml | 31 +++++---
7 files changed, 171 insertions(+), 97 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index 9b8548b38..b0dd9a41a 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -16,6 +16,7 @@ import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.post
+import io.ktor.server.routing.put
import io.ktor.server.routing.routing
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -26,6 +27,7 @@ import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSession
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
+import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
import org.horizontal.tella.mobile.data.peertopeer.remote.PeerApiRoutes
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.domain.peertopeer.FileInfo
@@ -35,6 +37,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.domain.peertopeer.PeerRegisterPayload
import org.horizontal.tella.mobile.domain.peertopeer.PeerResponse
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
+import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
import java.security.KeyPair
import java.security.KeyStore
@@ -43,7 +46,6 @@ import java.util.UUID
const val port = 53317
-//TODO THIS CLASS MUST BE INJECTED
class TellaPeerToPeerServer(
private val ip: String,
private val serverPort: Int = port,
@@ -143,6 +145,7 @@ class TellaPeerToPeerServer(
call.respond(HttpStatusCode.OK, session)
}
+
post(PeerApiRoutes.PREPARE_UPLOAD) {
val request = try {
call.receive()
@@ -190,7 +193,7 @@ class TellaPeerToPeerServer(
}
}
- post(PeerApiRoutes.UPLOAD) {
+ put(PeerApiRoutes.UPLOAD) {
val sessionId = call.parameters["sessionId"]
val fileId = call.parameters["fileId"]
val transmissionId = call.parameters["transmissionId"]
@@ -199,21 +202,19 @@ class TellaPeerToPeerServer(
if (sessionId == null || fileId == null || transmissionId == null) {
call.respond(HttpStatusCode.BadRequest, "Missing path parameters")
- return@post
+ return@put
}
- if (sessionId != p2PSharedState.session?.sessionId) {
- Timber.d("session Id")
+ val session = p2PSharedState.session
+ if (sessionId != session?.sessionId) {
call.respond(HttpStatusCode.Unauthorized, "Invalid session ID")
- return@post
+ return@put
}
- val session = p2PSharedState.session
- val progressFile = session?.files?.get(transmissionId)
-
+ val progressFile = session.files[transmissionId]
if (progressFile == null || progressFile.file.id != fileId) {
call.respond(HttpStatusCode.NotFound, "File not found in session")
- return@post
+ return@put
}
val tmpFile = createTempFile(prefix = "p2p_", suffix = "_$fileId")
@@ -221,6 +222,7 @@ class TellaPeerToPeerServer(
try {
val input = call.receiveStream().buffered()
+ val totalSize = session.files.values.sumOf { it.file.size }
var bytesRead = 0L
val buffer = ByteArray(8192)
@@ -229,42 +231,54 @@ class TellaPeerToPeerServer(
if (read == -1) break
output.write(buffer, 0, read)
bytesRead += read
-
progressFile.bytesTransferred = bytesRead.toInt()
- PeerEventManager.onUploadProgressState(
- p2PSharedState
+
+ // Optional: update session progress percent
+ val totalTransferred = session.files.values.sumOf { it.bytesTransferred }
+ val percent = if (totalSize > 0) ((totalTransferred * 100) / totalSize).toInt() else 0
+
+ val state = UploadProgressState(
+ percent = percent,
+ sessionStatus = session.status,
+ files = session.files.values.toList()
)
+ PeerEventManager.onUploadProgressState(state)
}
progressFile.status = P2PFileStatus.FINISHED
progressFile.path = tmpFile.absolutePath
+ // Final emit after completion
+ val finalState = UploadProgressState(
+ percent = 100,
+ sessionStatus = SessionStatus.FINISHED,
+ files = session.files.values.toList()
+ )
+ PeerEventManager.onUploadProgressState(finalState)
call.respond(HttpStatusCode.OK, "Upload complete")
} catch (e: Exception) {
progressFile.status = P2PFileStatus.FAILED
- call.respond(
- HttpStatusCode.InternalServerError,
- "Upload failed: ${e.message}"
+
+ val failedState = UploadProgressState(
+ percent = 0,
+ sessionStatus = session.status,
+ files = session.files.values.toList()
)
+ PeerEventManager.onUploadProgressState(failedState)
+
+ call.respond(HttpStatusCode.InternalServerError, "Upload failed: ${e.message}")
} finally {
output.close()
}
}
-
}
}
}).start(wait = false)
}
- private fun calculatePercent(files: Collection): Int {
- val uploaded = files.sumOf { it.bytesTransferred.toLong() }
- val total = files.sumOf { it.file.size }
- return if (total > 0) ((uploaded * 100) / total).toInt() else 0
- }
-
override fun stop() {
engine?.stop(1000, 5000)
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
index dbdbc292a..a1a1e765b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/PeerEventManager.kt
@@ -23,26 +23,8 @@ object PeerEventManager {
private val _uploadProgressStateFlow = MutableSharedFlow(replay = 1)
val uploadProgressStateFlow = _uploadProgressStateFlow.asSharedFlow()
-
- suspend fun onUploadProgressState(p2PSharedState : P2PSharedState) {
- val session = p2PSharedState.session
- val files = session?.files?.values?.toList() ?: emptyList()
-
- val totalSize = files.sumOf { it.file.size }
- val uploaded = files.sumOf { it.bytesTransferred }
- val percent = if (totalSize > 0) ((uploaded * 100) / totalSize).toInt() else 0
-
- val state = session?.status?.let {
- UploadProgressState(
- percent = percent,
- sessionStatus = it,
- files = files
- )
- }
-
- if (state != null) {
- _uploadProgressStateFlow.emit(state)
- }
+ suspend fun onUploadProgressState(state: UploadProgressState) {
+ _uploadProgressStateFlow.emit(state)
}
suspend fun emitRegistrationSuccess() {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index 061f15690..276e5cdc1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -1,7 +1,5 @@
package org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow
-import android.app.Activity
-import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
@@ -9,13 +7,12 @@ import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.R
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
+import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils.showStandardSheet
-import org.hzontal.shared_ui.utils.DialogUtils
-import timber.log.Timber
import javax.inject.Inject
@AndroidEntryPoint
@@ -44,7 +41,7 @@ class RecipientUploadFilesFragment :
{
PeerToPeerFlags.cancelled = true
baseActivity.finish()
- })
+ })
}
}
@@ -64,9 +61,18 @@ class RecipientUploadFilesFragment :
}
private fun observeUploadProgress() {
+
viewModel.uploadProgress.observe(viewLifecycleOwner) { state ->
- Timber.d("State "+ state?.percent + " Status: "+state?.sessionStatus?.name)
- }
+ if (state == null) return@observe
+ val files = state.files
+ val percentFloat = state.percent / 100f
+ endView.setUploadProgress(files, percentFloat)
+ // Optional: finalize UI when upload is done
+ if (state.sessionStatus == SessionStatus.FINISHED) {
+ endView.clearPartsProgress(files, SessionStatus.FINISHED)
+ }
+ }
}
+
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
index 362a25158..13b8391b1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
@@ -24,7 +24,7 @@ class PeerToPeerResultFragment :
// Get values from shared state
participant = PeerToPeerParticipant.SENDER
- transferredFiles = viewModel.p2PState.session.files.values.toList()
+ transferredFiles = viewModel.p2PState.session?.files?.values?.toList()
setupImage()
setupTexts()
@@ -47,7 +47,8 @@ class PeerToPeerResultFragment :
}
private fun setupTexts() {
- binding.tileTv.text = getString(if (allFilesTransferred) R.string.success_title else R.string.failure_title)
+ binding.tileTv.text =
+ getString(if (allFilesTransferred) R.string.success_title else R.string.failure_title)
binding.descriptionTv.text = computeSubtitle()
}
@@ -57,7 +58,7 @@ class PeerToPeerResultFragment :
setText(getString(R.string.view_files_action))
visibility = View.VISIBLE
setOnClickListener {
- // TODO: Implement button action
+ baseActivity.finish()
}
}
} else {
@@ -66,25 +67,33 @@ class PeerToPeerResultFragment :
}
private fun computeSubtitle(): String {
- val total = transferredFiles?.size
- val successCount = transferredFiles?.count { it.status == successStatus }
- val failureCount = total?.minus(successCount!!)
-
- return when {
- successCount == total -> getString(if (total == 1) successSingleRes() else successMultipleRes(), total)
- failureCount == total -> getString(if (total == 1) failureSingleRes() else failureMultipleRes(), total)
+ val total = transferredFiles?.size ?: 0
+ val successCount = transferredFiles?.count { it.status == successStatus } ?: 0
+ val failureCount = total - successCount
+
+ return when (successCount) {
+ total -> {
+ val resId = if (participant == PeerToPeerParticipant.RECIPIENT)
+ R.plurals.success_file_received_from_sender
+ else
+ R.plurals.success_file_sent_to_recipient
+
+ return resources.getQuantityString(resId, total, total)
+ }
+ 0 -> {
+ baseActivity.resources.getQuantityString(
+ R.plurals.failure_file_received_expl,
+ failureCount,
+ failureCount
+ )
+ }
else -> {
- val resId = when {
- successCount == 1 && failureCount == 1 -> R.string.file_received_file_not_received
- successCount == 1 -> R.string.file_received_files_not_received
- failureCount == 1 -> R.string.files_received_file_not_received
- else -> R.string.files_received_files_not_received
- }
- getString(resId, successCount, failureCount)
+ getString(R.string.partial_success_summary, successCount, failureCount)
}
}
}
+
private val successStatus: P2PFileStatus
get() = P2PFileStatus.FINISHED
@@ -94,18 +103,4 @@ class PeerToPeerResultFragment :
private val noFilesTransferred: Boolean
get() = transferredFiles?.none { it.status == successStatus } == true
- private fun successSingleRes(): Int =
- if (participant == PeerToPeerParticipant.RECIPIENT)
- R.string.success_file_received_expl
- else
- R.string.success_file_sent_expl
-
- private fun successMultipleRes(): Int =
- if (participant == PeerToPeerParticipant.RECIPIENT)
- R.string.success_files_received_expl
- else
- R.string.success_files_sent_expl
-
- private fun failureSingleRes(): Int = R.string.failure_file_received_expl
- private fun failureMultipleRes(): Int = R.string.failure_files_received_expl
}
\ No newline at end of file
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index c572fe5d9..2b372e2e2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -6,25 +6,35 @@ import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.hzontal.tella_vault.VaultFile
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.bus.SingleLiveEvent
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
import org.horizontal.tella.mobile.data.peertopeer.ServerPinger
import org.horizontal.tella.mobile.data.peertopeer.TellaPeerToPeerClient
import org.horizontal.tella.mobile.data.peertopeer.managers.PeerToPeerManager
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
+import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
+import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
import org.horizontal.tella.mobile.data.peertopeer.remote.PrepareUploadRequest
import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
+import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
+import java.io.File
+import java.io.FileInputStream
import javax.inject.Inject
@HiltViewModel
@@ -35,7 +45,7 @@ class PeerToPeerViewModel @Inject constructor(
val p2PState: P2PSharedState
) : ViewModel() {
- var isManualConnection: Boolean = true // default is manual
+ var isManualConnection: Boolean = true
var hasNavigatedToSuccessFragment = false
var currentNetworkInfo: NetworkInfo? = null
private val _registrationSuccess = SingleLiveEvent()
@@ -82,7 +92,20 @@ class PeerToPeerViewModel @Inject constructor(
viewModelScope.launch {
PeerEventManager.uploadProgressStateFlow.collect { state ->
+ _uploadProgress.postValue(state)
+ }
+ }
+
+ viewModelScope.launch {
+ PeerEventManager.uploadProgressStateFlow.collect { state ->
+ _uploadProgress.postValue(state)
+
+ val allFinished = state.files.all { it.status == P2PFileStatus.FINISHED }
+ val alreadySaved = state.sessionStatus == SessionStatus.FINISHED
+ if (allFinished && !alreadySaved) {
+ finalizeAndSaveReceivedFiles(state.files)
+ }
}
}
}
@@ -195,6 +218,56 @@ class PeerToPeerViewModel @Inject constructor(
hasNavigatedToSuccessFragment = false
}
+ private fun finalizeAndSaveReceivedFiles(progressFiles: List) {
+ viewModelScope.launch(Dispatchers.IO) {
+ val vault = MyApplication.keyRxVault.rxVault.blockingFirst()
+ val root = vault.root.blockingGet()
+ val folder = vault.builder()
+ .setName("Received_" + System.currentTimeMillis())
+ .setType(VaultFile.Type.DIRECTORY)
+ .build(root.id)
+ .blockingGet()
+
+ progressFiles.forEach { progressFile ->
+ try {
+ val path = progressFile.path ?: return@forEach
+ val file = File(path)
+ if (!file.exists()) return@forEach
+
+ val vaultFile = when (file.extension.lowercase()) {
+ "jpg", "jpeg" -> MediaFileHandler.saveJpegPhoto(file.readBytes(), folder.id).blockingGet()
+ "png" -> MediaFileHandler.savePngImage(file.readBytes())
+ "mp4" -> MediaFileHandler.saveMp4Video(file, folder.id)
+ else -> vault.builder(FileInputStream(file))
+ .setName(file.name)
+ .setType(VaultFile.Type.FILE)
+ .build(folder.id)
+ .blockingGet()
+ }
+
+ progressFile.vaultFile = vaultFile
+
+ } catch (e: Exception) {
+ Timber.e(e, "Saving to vault failed for file ${progressFile.file.fileName}")
+ progressFile.status = P2PFileStatus.FAILED
+ }
+ }
+
+ // Optional: Update final session state
+ p2PState.session?.status = SessionStatus.FINISHED
+
+ // Re-emit new state with VaultFiles linked
+ _uploadProgress.postValue(
+ UploadProgressState(
+ percent = 100,
+ sessionStatus = SessionStatus.FINISHED,
+ files = progressFiles
+ )
+ )
+ }
+ }
+
+
override fun onCleared() {
super.onCleared()
p2PState.clear()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt
index b2f3c2517..00f5e31d7 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/attachements/AttachmentsViewModel.kt
@@ -105,7 +105,6 @@ class AttachmentsViewModel @Inject constructor(
)
}
-
fun moveFiles(parentId: String?, vaultFiles: List?) {
if (vaultFiles == null || parentId == null) return
@@ -169,7 +168,6 @@ class AttachmentsViewModel @Inject constructor(
)
}
-
private fun deleteFile(vaultFile: VaultFile): Single {
return MyApplication.keyRxVault.rxVault
.firstOrError()
@@ -178,7 +176,6 @@ class AttachmentsViewModel @Inject constructor(
.observeOn(AndroidSchedulers.mainThread())
}
-
fun createFolder(folderName: String, parent: String) {
disposables.add(
MyApplication.keyRxVault.rxVault
diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml
index da4d2c6ba..c5800651c 100644
--- a/mobile/src/main/res/values/strings.xml
+++ b/mobile/src/main/res/values/strings.xml
@@ -1048,13 +1048,13 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
Exit nearby sharing?
Your progress will be lost.
IP address
- Sender\'s files rejected.
+ Sender\'s files rejected.
"The receiver accepted the files transfer "
Recipient rejected the files.
Receiving and encrypting files
Sending files
Send files
- Location permission is required to get WiFi SSID.
+ Location permission is required to get WiFi SSID.
Failed to open location settings.
Try again
Stop sharing files?
@@ -1062,16 +1062,23 @@ You can create your own Wi-Fi network\n using your phone’s hotspot feature.\n
stop
Success
Something went wrong
- You have successfully received %d file.
- You have successfully received %d files.
- You have successfully sent %d file.
- You have successfully sent %d files.
- We couldn't receive %d file.
- We couldn't receive %d files.
- 1 file received, 1 file not received
- 1 file received, %d files not received
- %d files received, 1 file not received
- %d files received, %d files not received
+
+
+ - You have successfully received %1$d file from the sender.
+ - You have successfully received %1$d files from the sender.
+
+
+
+ - You have successfully sent %1$d file to the recipient.
+ - You have successfully sent %1$d files to the recipient.
+
+
+ Only %1$d files were received. %2$d files were not received.
+
+ - 0 files were received. %1$d file was not received.
+ - 0 files were received. %1$d files were not received.
+
+
View Files
VIEW FILES
From 8818868642cfccf6f28cf91312b65eef8f20e6b3 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 16 Jul 2025 21:10:50 +0100
Subject: [PATCH 084/153] WIP save files in the recepient
---
.../data/peertopeer/TellaPeerToPeerClient.kt | 8 ++-
.../data/peertopeer/TellaPeerToPeerServer.kt | 12 +++-
.../tella/mobile/domain/peertopeer/P2PFile.kt | 2 +-
.../RecipientUploadFilesFragment.kt | 4 --
.../senderflow/PrepareUploadFragment.kt | 3 +-
.../viewmodel/FileTransferViewModel.kt | 3 +
.../viewmodel/PeerToPeerViewModel.kt | 57 ++++++++++++-------
.../viewmodel/state/UploadProgressState.kt | 1 +
.../uwazi/widgets/PeerToPeerEndView.java | 57 +++++++++++++------
9 files changed, 99 insertions(+), 48 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
index f37890552..daec37b6f 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerClient.kt
@@ -33,7 +33,7 @@ import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
-class TellaPeerToPeerClient @Inject constructor(){
+class TellaPeerToPeerClient @Inject constructor() {
private fun getClientWithFingerprintValidation(expectedFingerprint: String): OkHttpClient {
val trustManager = object : X509TrustManager {
@@ -136,7 +136,8 @@ class TellaPeerToPeerClient @Inject constructor(){
fileName = it.name,
size = it.size,
fileType = mimeType,
- sha256 = it.hash
+ sha256 = it.hash,
+ thumb = it.thumb
)
}
@@ -177,6 +178,7 @@ class TellaPeerToPeerClient @Inject constructor(){
PrepareUploadResult.Failure(Exception("Malformed server response"))
}
}
+
private fun handleServerError(code: Int, body: String): PrepareUploadResult {
return when (code) {
400 -> PrepareUploadResult.BadRequest
@@ -208,7 +210,7 @@ class TellaPeerToPeerClient @Inject constructor(){
val request = Request.Builder()
.url(url)
- .post(requestBody)
+ .put(requestBody)
.addHeader(CONTENT_TYPE, CONTENT_TYPE_OCTET)
.build()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
index b0dd9a41a..c43e084f1 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/TellaPeerToPeerServer.kt
@@ -39,10 +39,13 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerResponse
import org.horizontal.tella.mobile.domain.peertopeer.TellaServer
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
+import java.io.File
import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.util.UUID
+import kotlin.io.path.outputStream
+import kotlin.io.path.pathString
const val port = 53317
@@ -217,7 +220,7 @@ class TellaPeerToPeerServer(
return@put
}
- val tmpFile = createTempFile(prefix = "p2p_", suffix = "_$fileId")
+ val tmpFile = File.createTempFile(fileId, ".tmp")
val output = tmpFile.outputStream().buffered()
try {
@@ -238,6 +241,7 @@ class TellaPeerToPeerServer(
val percent = if (totalSize > 0) ((totalTransferred * 100) / totalSize).toInt() else 0
val state = UploadProgressState(
+ title = session.title ?: "",
percent = percent,
sessionStatus = session.status,
files = session.files.values.toList()
@@ -246,14 +250,15 @@ class TellaPeerToPeerServer(
}
progressFile.status = P2PFileStatus.FINISHED
- progressFile.path = tmpFile.absolutePath
+ progressFile.path = tmpFile.path
- // Final emit after completion
val finalState = UploadProgressState(
+ title = session.title ?: "",
percent = 100,
sessionStatus = SessionStatus.FINISHED,
files = session.files.values.toList()
)
+
PeerEventManager.onUploadProgressState(finalState)
call.respond(HttpStatusCode.OK, "Upload complete")
@@ -261,6 +266,7 @@ class TellaPeerToPeerServer(
progressFile.status = P2PFileStatus.FAILED
val failedState = UploadProgressState(
+ title = session.title ?: "",
percent = 0,
sessionStatus = session.status,
files = session.files.values.toList()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt
index c4a6db2d8..43fc2e92b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/domain/peertopeer/P2PFile.kt
@@ -9,7 +9,7 @@ data class P2PFile(
val size: Long,
val fileType: String,
val sha256: String,
- val thumb: ByteArray? = null
+ val thumb: ByteArray
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index 276e5cdc1..952a2d3a2 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -68,10 +68,6 @@ class RecipientUploadFilesFragment :
val percentFloat = state.percent / 100f
endView.setUploadProgress(files, percentFloat)
- // Optional: finalize UI when upload is done
- if (state.sessionStatus == SessionStatus.FINISHED) {
- endView.clearPartsProgress(files, SessionStatus.FINISHED)
- }
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
index 5c086f855..4a7e44303 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PrepareUploadFragment.kt
@@ -267,7 +267,8 @@ class PrepareUploadFragment :
fileName = vaultFile.name,
size = vaultFile.size,
fileType = vaultFile.mimeType ?: "application/octet-stream",
- sha256 = vaultFile.hash
+ sha256 = vaultFile.hash,
+ thumb = vaultFile.thumb
)
val progressFile = ProgressFile(
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
index b3b4b9059..07b6bf5cf 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
@@ -139,6 +139,7 @@ class FileTransferViewModel @Inject constructor(
_uploadProgress.postValue(
UploadProgressState(
+ title = session.title ?: "",
percent = percent,
sessionStatus = session.status,
files = session.files.values.toList()
@@ -158,6 +159,7 @@ class FileTransferViewModel @Inject constructor(
// Post state after each file is done
_uploadProgress.postValue(
UploadProgressState(
+ title = session.title ?: "",
percent = session.files.values.sumOf { it.bytesTransferred }.let {
if (totalSize > 0) ((it * 100) / totalSize).toInt() else 0
},
@@ -172,6 +174,7 @@ class FileTransferViewModel @Inject constructor(
// Final update after all uploads complete
_uploadProgress.postValue(
UploadProgressState(
+ title = session.title ?: "",
percent = 100,
sessionStatus = session.status,
files = session.files.values.toList()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index 2b372e2e2..047efee3d 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -13,7 +13,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.bus.SingleLiveEvent
import org.horizontal.tella.mobile.data.peertopeer.FingerprintFetcher
@@ -29,12 +28,12 @@ import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.media.MediaFileHandler
+import org.horizontal.tella.mobile.util.FileUtil.getMimeType
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
import java.io.File
-import java.io.FileInputStream
import javax.inject.Inject
@HiltViewModel
@@ -65,6 +64,8 @@ class PeerToPeerViewModel @Inject constructor(
val networkInfo: LiveData get() = networkInfoManager.networkInfo
private val _uploadProgress = SingleLiveEvent()
val uploadProgress: SingleLiveEvent = _uploadProgress
+ private var isVaultSaveDone = false
+
init {
viewModelScope.launch {
@@ -92,22 +93,16 @@ class PeerToPeerViewModel @Inject constructor(
viewModelScope.launch {
PeerEventManager.uploadProgressStateFlow.collect { state ->
- _uploadProgress.postValue(state)
- }
- }
-
- viewModelScope.launch {
- PeerEventManager.uploadProgressStateFlow.collect { state ->
- _uploadProgress.postValue(state)
val allFinished = state.files.all { it.status == P2PFileStatus.FINISHED }
- val alreadySaved = state.sessionStatus == SessionStatus.FINISHED
- if (allFinished && !alreadySaved) {
- finalizeAndSaveReceivedFiles(state.files)
+ if (allFinished && !isVaultSaveDone) {
+ isVaultSaveDone = true // prevent re-saving
+ finalizeAndSaveReceivedFiles(p2PState.session?.title.orEmpty(), state.files)
}
}
}
+
}
fun resetRegistrationState() {
@@ -218,34 +213,58 @@ class PeerToPeerViewModel @Inject constructor(
hasNavigatedToSuccessFragment = false
}
- private fun finalizeAndSaveReceivedFiles(progressFiles: List) {
+ private fun finalizeAndSaveReceivedFiles(
+ folderName: String,
+ progressFiles: List
+ ) {
viewModelScope.launch(Dispatchers.IO) {
val vault = MyApplication.keyRxVault.rxVault.blockingFirst()
val root = vault.root.blockingGet()
+
val folder = vault.builder()
- .setName("Received_" + System.currentTimeMillis())
+ .setName(folderName)
.setType(VaultFile.Type.DIRECTORY)
.build(root.id)
.blockingGet()
+ val totalFiles = progressFiles.size
+ var savedFiles = 0
+
progressFiles.forEach { progressFile ->
try {
val path = progressFile.path ?: return@forEach
val file = File(path)
if (!file.exists()) return@forEach
- val vaultFile = when (file.extension.lowercase()) {
- "jpg", "jpeg" -> MediaFileHandler.saveJpegPhoto(file.readBytes(), folder.id).blockingGet()
+ val vaultFile = when (progressFile.file.fileType) {
+ "jpg", "jpeg" -> MediaFileHandler.saveJpegPhoto(file.readBytes(), folder.id)
+ .blockingGet()
+
"png" -> MediaFileHandler.savePngImage(file.readBytes())
"mp4" -> MediaFileHandler.saveMp4Video(file, folder.id)
- else -> vault.builder(FileInputStream(file))
+ else -> vault.builder(file.inputStream())
.setName(file.name)
+ .setMimeType(progressFile.file.fileType)
.setType(VaultFile.Type.FILE)
.build(folder.id)
.blockingGet()
}
progressFile.vaultFile = vaultFile
+ savedFiles++
+
+ // Delete temp file after saving
+ file.delete()
+
+ // Emit progress after each file
+ _uploadProgress.postValue(
+ UploadProgressState(
+ title = folderName,
+ percent = ((savedFiles * 100) / totalFiles),
+ sessionStatus = SessionStatus.SENDING,
+ files = progressFiles
+ )
+ )
} catch (e: Exception) {
Timber.e(e, "Saving to vault failed for file ${progressFile.file.fileName}")
@@ -253,12 +272,11 @@ class PeerToPeerViewModel @Inject constructor(
}
}
- // Optional: Update final session state
p2PState.session?.status = SessionStatus.FINISHED
- // Re-emit new state with VaultFiles linked
_uploadProgress.postValue(
UploadProgressState(
+ title = folderName,
percent = 100,
sessionStatus = SessionStatus.FINISHED,
files = progressFiles
@@ -267,7 +285,6 @@ class PeerToPeerViewModel @Inject constructor(
}
}
-
override fun onCleared() {
super.onCleared()
p2PState.clear()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt
index e8ca736e4..b41d36381 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/state/UploadProgressState.kt
@@ -4,6 +4,7 @@ import org.horizontal.tella.mobile.data.peertopeer.model.ProgressFile
import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
data class UploadProgressState(
+ val title: String,
val percent: Int,
val sessionStatus: SessionStatus,
val files: List
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
index 573af2234..2f3f2b445 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
@@ -66,8 +66,12 @@ public void setUploadProgress(List progressFiles, float pct) {
int percentComplete = getTotalUploadedSizePercent(progressFiles);
for (ProgressFile file : progressFiles) {
- if (file.getStatus() == P2PFileStatus.FINISHED && file.getVaultFile() != null) {
- SubmittingItem item = partsListView.findViewWithTag(file.getVaultFile().id);
+ String tagId = file.getVaultFile() != null && file.getVaultFile().id != null
+ ? file.getVaultFile().id
+ : file.getFile().getId();
+
+ if (file.getStatus() == P2PFileStatus.FINISHED) {
+ SubmittingItem item = partsListView.findViewWithTag(tagId);
if (item != null) item.setPartUploaded();
}
}
@@ -76,12 +80,13 @@ public void setUploadProgress(List progressFiles, float pct) {
setFormSizeLabel(progressFiles, percentComplete);
}
-
public void clearPartsProgress(List progressFiles, SessionStatus sessionStatus) {
for (ProgressFile file : progressFiles) {
- if (file.getVaultFile() == null) continue;
+ String tagId = file.getVaultFile() != null && file.getVaultFile().id != null
+ ? file.getVaultFile().id
+ : file.getFile().getId();
- SubmittingItem item = partsListView.findViewWithTag(file.getVaultFile().id);
+ SubmittingItem item = partsListView.findViewWithTag(tagId);
if (item != null) {
if (sessionStatus == SessionStatus.FINISHED || file.getStatus() == P2PFileStatus.FINISHED) {
item.setPartUploaded();
@@ -98,9 +103,12 @@ private int getTotalUploadedSizePercent(List progressFiles) {
for (ProgressFile file : progressFiles) {
totalUploadedSize += file.getBytesTransferred();
- if (file.getVaultFile() != null) {
- totalSize += file.getVaultFile().size;
- }
+
+ long size = file.getVaultFile() != null && file.getVaultFile().size > 0
+ ? file.getVaultFile().size
+ : file.getFile().getSize();
+
+ totalSize += size;
}
return totalSize > 0 ? Math.round((totalUploadedSize * 1f / totalSize) * 100) : 0;
@@ -112,9 +120,11 @@ private void setFormSizeLabel(List files, int percent) {
long totalUploaded = 0;
for (ProgressFile file : files) {
- if (file.getVaultFile() != null) {
- totalSize += file.getVaultFile().size;
- }
+ long size = file.getVaultFile() != null && file.getVaultFile().size > 0
+ ? file.getVaultFile().size
+ : file.getFile().getSize();
+
+ totalSize += size;
totalUploaded += file.getBytesTransferred();
}
@@ -136,14 +146,29 @@ private void uploadProgressVisibility(List files, boolean isOnline
private View createProgressFileItemView(@NonNull ProgressFile file, boolean offline) {
SubmittingItem item = new SubmittingItem(getContext(), null, 0);
ImageView thumbView = item.findViewById(R.id.fileThumb);
- item.setTag(file.getVaultFile() != null ? file.getVaultFile().id : file.getFile().getId());
- item.setPartName(file.getFile().getFileName());
- item.setPartSize(file.getFile().getSize());
+ String tagId = file.getVaultFile() != null && file.getVaultFile().id != null
+ ? file.getVaultFile().id
+ : file.getFile().getId();
+ item.setTag(tagId);
+
+ String name = file.getVaultFile() != null && file.getVaultFile().name != null
+ ? file.getVaultFile().name
+ : file.getFile().getFileName();
+ item.setPartName(name);
+
+ long size = file.getVaultFile() != null && file.getVaultFile().size > 0
+ ? file.getVaultFile().size
+ : file.getFile().getSize();
+ item.setPartSize(size);
+
+ byte[] thumb = file.getVaultFile() != null && file.getVaultFile().thumb != null
+ ? file.getVaultFile().thumb
+ : file.getFile().getThumb();
- if (file.getVaultFile() != null && file.getVaultFile().thumb != null) {
+ if (thumb != null) {
Glide.with(getContext())
- .load(file.getVaultFile().thumb)
+ .load(thumb)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(thumbView);
From 14fb06bb32252a1311aec61813977e987b3c7219 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 16 Jul 2025 21:44:14 +0100
Subject: [PATCH 085/153] Finish saving files in DB
---
.../viewmodel/PeerToPeerViewModel.kt | 47 ++++++++++++++-----
1 file changed, 34 insertions(+), 13 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index 047efee3d..aa61aba0b 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -2,11 +2,15 @@ package org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel
import android.content.Context
import android.os.Build
+import android.os.Environment
import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.hzontal.tella_vault.VaultFile
+import com.hzontal.utils.MediaFile.isAudioFileType
+import com.hzontal.utils.MediaFile.isImageFileType
+import com.hzontal.utils.MediaFile.isVideoFileType
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
@@ -28,7 +32,6 @@ import org.horizontal.tella.mobile.data.peertopeer.remote.RegisterPeerResult
import org.horizontal.tella.mobile.domain.peertopeer.IncomingRegistration
import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.media.MediaFileHandler
-import org.horizontal.tella.mobile.util.FileUtil.getMimeType
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
@@ -236,20 +239,38 @@ class PeerToPeerViewModel @Inject constructor(
val file = File(path)
if (!file.exists()) return@forEach
- val vaultFile = when (progressFile.file.fileType) {
- "jpg", "jpeg" -> MediaFileHandler.saveJpegPhoto(file.readBytes(), folder.id)
- .blockingGet()
-
- "png" -> MediaFileHandler.savePngImage(file.readBytes())
- "mp4" -> MediaFileHandler.saveMp4Video(file, folder.id)
- else -> vault.builder(file.inputStream())
- .setName(file.name)
- .setMimeType(progressFile.file.fileType)
- .setType(VaultFile.Type.FILE)
- .build(folder.id)
- .blockingGet()
+ val vaultFile = try {
+ when {
+ isImageFileType(progressFile.file.fileType) -> {
+ val imageBytes = file.readBytes()
+ if (progressFile.file.fileType.contains("png", ignoreCase = true)) {
+ MediaFileHandler.savePngImage(imageBytes)
+ } else {
+ MediaFileHandler.saveJpegPhoto(imageBytes, folder.id)
+ .blockingGet()
+ }
+ }
+
+ isVideoFileType(progressFile.file.fileType) -> {
+ MediaFileHandler.saveMp4Video(file, folder.id)
+ }
+
+ else -> {
+ vault.builder(file.inputStream())
+ .setName(file.name)
+ .setMimeType(progressFile.file.fileType)
+ .setType(VaultFile.Type.FILE)
+ .build(folder.id)
+ .blockingGet()
+ }
+ }
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to save file ${progressFile.file.fileName}")
+ null
}
+
+
progressFile.vaultFile = vaultFile
savedFiles++
From 07524d7c34a0d17e8321bc95cf96f66d43c3b3d2 Mon Sep 17 00:00:00 2001
From: Ahlem
Date: Wed, 16 Jul 2025 22:21:27 +0100
Subject: [PATCH 086/153] wip finish peer to peer result
---
.../data/peertopeer/model/P2PFileStatus.kt | 3 ++-
.../tella/mobile/util/NavigationManager.kt | 11 ++++++++++-
.../RecipientUploadFilesFragment.kt | 10 ++++++++++
.../senderflow/PeerToPeerResultFragment.kt | 4 +---
.../senderflow/SenderUploadFilesFragment.kt | 10 ++++++++++
.../viewmodel/FileTransferViewModel.kt | 2 ++
.../viewmodel/PeerToPeerViewModel.kt | 5 +++--
.../main/res/navigation/peer_to_peer_graph.xml | 18 ++++++++++++++++--
8 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
index 1a3f7d1c2..cd10bd3a4 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
@@ -4,5 +4,6 @@ enum class P2PFileStatus {
QUEUE,
SENDING,
FAILED,
- FINISHED
+ FINISHED,
+ SAVED,
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
index ddb249c4e..7eaca5738 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/util/NavigationManager.kt
@@ -224,12 +224,21 @@ class NavigationManager(
fun navigateFromWaitingSenderFragmentToUploadFilesFragment() {
navigateToWithBundle(R.id.action_waitingSenderFragment_to_uploadFilesFragment)
- }
+ }
+
+ fun navigateFromUploadSenderFragmentToPeerToPeerResultFragment() {
+ navigateToWithBundle(R.id.action_uploadSenderFragment_to_peerToPeerResultFragment)
+ }
+
+ fun navigateFromRecipientUploadFilesFragmentToPeerToPeerResultFragment() {
+ navigateToWithBundle(R.id.action_recipientUploadFilesFragment_to_peerToPeerResultFragment)
+ }
fun navigateFromRecipientSuccessFragmentToRecipientUploadFilesFragment() {
navigateToWithBundle(R.id.action_recipientSuccessFragment_to_recipientUploadFilesFragment)
}
+
fun navigateBackToStartNearBySharingFragmentAndClearBackStack() {
navControllerProvider.navController.navigate(
R.id.startNearBySharingFragment,
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
index 952a2d3a2..8671ea911 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/RecipientUploadFilesFragment.kt
@@ -6,10 +6,12 @@ import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
import org.horizontal.tella.mobile.data.peertopeer.model.P2PSharedState
import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
+import org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow.PeerToPeerParticipant
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.PeerToPeerViewModel
import org.horizontal.tella.mobile.views.fragment.uwazi.widgets.PeerToPeerEndView
import org.hzontal.shared_ui.bottomsheet.BottomSheetUtils.showStandardSheet
@@ -30,6 +32,8 @@ class RecipientUploadFilesFragment :
super.onViewCreated(view, savedInstanceState)
showFormEndView()
observeUploadProgress()
+ viewModel.peerToPeerParticipant = PeerToPeerParticipant.RECIPIENT
+
binding.cancel.setOnClickListener {
showStandardSheet(
baseActivity.supportFragmentManager,
@@ -68,6 +72,12 @@ class RecipientUploadFilesFragment :
val percentFloat = state.percent / 100f
endView.setUploadProgress(files, percentFloat)
+ val allSaved = state.files.all { it.status == P2PFileStatus.SAVED }
+
+ if (state.sessionStatus == SessionStatus.FINISHED && allSaved) {
+ navManager().navigateFromRecipientUploadFilesFragmentToPeerToPeerResultFragment()
+ }
+
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
index 13b8391b1..14bc6dd98 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/PeerToPeerResultFragment.kt
@@ -16,14 +16,12 @@ class PeerToPeerResultFragment :
BaseBindingFragment(FragmentPeerToPeerResultBinding::inflate) {
private val viewModel: PeerToPeerViewModel by activityViewModels()
- private lateinit var participant: PeerToPeerParticipant
private var transferredFiles: List? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Get values from shared state
- participant = PeerToPeerParticipant.SENDER
transferredFiles = viewModel.p2PState.session?.files?.values?.toList()
setupImage()
@@ -73,7 +71,7 @@ class PeerToPeerResultFragment :
return when (successCount) {
total -> {
- val resId = if (participant == PeerToPeerParticipant.RECIPIENT)
+ val resId = if (viewModel.peerToPeerParticipant == PeerToPeerParticipant.RECIPIENT)
R.plurals.success_file_received_from_sender
else
R.plurals.success_file_sent_to_recipient
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
index 37a30da26..b3bf9cf62 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/senderflow/SenderUploadFilesFragment.kt
@@ -5,6 +5,8 @@ import android.view.View
import androidx.fragment.app.activityViewModels
import org.horizontal.tella.mobile.MyApplication
import org.horizontal.tella.mobile.R
+import org.horizontal.tella.mobile.data.peertopeer.model.P2PFileStatus
+import org.horizontal.tella.mobile.data.peertopeer.model.SessionStatus
import org.horizontal.tella.mobile.databinding.FragmentUploadFilesBinding
import org.horizontal.tella.mobile.views.base_ui.BaseBindingFragment
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.FileTransferViewModel
@@ -20,6 +22,7 @@ class SenderUploadFilesFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.uploadAllFiles()
+ viewModel.peerToPeerParticipant = PeerToPeerParticipant.SENDER
showFormEndView()
observeUploadProgress()
viewModel.uploadAllFiles()
@@ -54,6 +57,13 @@ class SenderUploadFilesFragment :
val files = state.files
val percentFloat = state.percent / 100f
endView.setUploadProgress(files, percentFloat)
+
+
+ val allFinished = state.files.all { it.status == P2PFileStatus.FINISHED }
+
+ if (state.sessionStatus == SessionStatus.FINISHED && allFinished) {
+ navManager().navigateFromUploadSenderFragmentToPeerToPeerResultFragment()
+ }
}
}
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
index 07b6bf5cf..c40403619 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/FileTransferViewModel.kt
@@ -23,6 +23,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerPrepareUploadResponse
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.Event
import org.horizontal.tella.mobile.util.fromJsonToObjectList
+import org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow.PeerToPeerParticipant
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
import javax.inject.Inject
@@ -38,6 +39,7 @@ class FileTransferViewModel @Inject constructor(
val prepareRejected: LiveData> = _prepareRejected
private val _uploadProgress = MutableLiveData()
val uploadProgress: LiveData get() = _uploadProgress
+ var peerToPeerParticipant: PeerToPeerParticipant = PeerToPeerParticipant.SENDER
fun putVaultFilesInForm(vaultFileList: String): Single> {
return Single.fromCallable {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index aa61aba0b..927df4234 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -34,6 +34,7 @@ import org.horizontal.tella.mobile.domain.peertopeer.PeerEventManager
import org.horizontal.tella.mobile.media.MediaFileHandler
import org.horizontal.tella.mobile.util.NetworkInfo
import org.horizontal.tella.mobile.util.NetworkInfoManager
+import org.horizontal.tella.mobile.views.fragment.peertopeer.senderflow.PeerToPeerParticipant
import org.horizontal.tella.mobile.views.fragment.peertopeer.viewmodel.state.UploadProgressState
import timber.log.Timber
import java.io.File
@@ -46,7 +47,7 @@ class PeerToPeerViewModel @Inject constructor(
peerToPeerManager: PeerToPeerManager,
val p2PState: P2PSharedState
) : ViewModel() {
-
+ var peerToPeerParticipant: PeerToPeerParticipant = PeerToPeerParticipant.SENDER
var isManualConnection: Boolean = true
var hasNavigatedToSuccessFragment = false
var currentNetworkInfo: NetworkInfo? = null
@@ -270,7 +271,7 @@ class PeerToPeerViewModel @Inject constructor(
}
-
+ p2PState.session?.files?.get(progressFile.file.id)?.status = P2PFileStatus.SAVED
progressFile.vaultFile = vaultFile
savedFiles++
diff --git a/mobile/src/main/res/navigation/peer_to_peer_graph.xml b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
index c16a8bc82..6f3ff107b 100644
--- a/mobile/src/main/res/navigation/peer_to_peer_graph.xml
+++ b/mobile/src/main/res/navigation/peer_to_peer_graph.xml
@@ -92,7 +92,11 @@
android:id="@+id/recipientUploadFilesFragment"
android:name="org.horizontal.tella.mobile.views.fragment.peertopeer.receipentflow.RecipientUploadFilesFragment"
android:label="recipientUploadFilesFragment"
- tools:layout="@layout/fragment_upload_files" />
+ tools:layout="@layout/fragment_upload_files" >
+
+
+ tools:layout="@layout/fragment_upload_files" >
+
+
+
+
\ No newline at end of file
From 633df7e04242be6a98ef79d28f1937afedd76d6f Mon Sep 17 00:00:00 2001
From: wafa
Date: Thu, 17 Jul 2025 08:47:02 +0100
Subject: [PATCH 087/153] WIP fix design and result progress state
---
.../data/peertopeer/model/P2PFileStatus.kt | 6 +---
.../receipentflow/ConnectHotspotFragment.kt | 3 +-
.../viewmodel/PeerToPeerViewModel.kt | 6 +++-
.../uwazi/widgets/PeerToPeerEndView.java | 27 +++++++++---------
.../adapters/connections/ServerViewHolder.kt | 2 +-
mobile/src/main/res/drawable/ic_p2p.xml | 19 ++++++++++++
.../src/main/res/drawable/ic_p2p_sharing.png | Bin 0 -> 1539 bytes
.../res/layout/connect_hotspot_layout.xml | 7 -----
.../src/main/res/layout/fragment_qr_code.xml | 3 +-
.../layout/start_near_by_sharing_fragment.xml | 10 +++++--
mobile/src/main/res/values/strings.xml | 2 +-
mobile/src/main/res/values/styles.xml | 3 --
.../hzontal/shared_ui/buttons/RoundButton.kt | 25 ++++++++++++----
.../res/drawable/bg_rounded_information.xml | 19 ++++++++++++
.../res/layout/dual_text_check_layout.xml | 2 +-
.../main/res/layout/layout_round_button.xml | 1 +
shared-ui/src/main/res/values/attrs.xml | 2 ++
17 files changed, 93 insertions(+), 44 deletions(-)
create mode 100644 mobile/src/main/res/drawable/ic_p2p.xml
create mode 100644 mobile/src/main/res/drawable/ic_p2p_sharing.png
create mode 100644 shared-ui/src/main/res/drawable/bg_rounded_information.xml
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
index cd10bd3a4..766205915 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/peertopeer/model/P2PFileStatus.kt
@@ -1,9 +1,5 @@
package org.horizontal.tella.mobile.data.peertopeer.model
enum class P2PFileStatus {
- QUEUE,
- SENDING,
- FAILED,
- FINISHED,
- SAVED,
+ QUEUE, SENDING, FINISHED, SAVED, FAILED
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
index c14b50ef8..501707d97 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/receipentflow/ConnectHotspotFragment.kt
@@ -81,7 +81,6 @@ class ConnectHotspotFragment :
}
binding.toolbar.backClickListener = { baseActivity.onBackPressed() }
- binding.backBtn.setOnClickListener { baseActivity.onBackPressed() }
}
private fun updateNextButtonState(connectionType: ConnectionType?) {
@@ -110,7 +109,7 @@ class ConnectHotspotFragment :
if (ContextCompat.checkSelfPermission(baseActivity, ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
- baseActivity.maybeChangeTemporaryTimeout{
+ baseActivity.maybeChangeTemporaryTimeout {
requestPermissionLauncher.launch(ACCESS_FINE_LOCATION)
}
} else {
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
index 927df4234..a1f5fbca3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/peertopeer/viewmodel/PeerToPeerViewModel.kt
@@ -270,8 +270,10 @@ class PeerToPeerViewModel @Inject constructor(
null
}
+ // Update both the shared session and local progress file status
+ p2PState.session?.files?.get(progressFile.file.id)?.status = P2PFileStatus.SAVED
+ progressFile.status = P2PFileStatus.SAVED // <-- Important!
- p2PState.session?.files?.get(progressFile.file.id)?.status = P2PFileStatus.SAVED
progressFile.vaultFile = vaultFile
savedFiles++
@@ -294,6 +296,7 @@ class PeerToPeerViewModel @Inject constructor(
}
}
+ // ✅ Final session status
p2PState.session?.status = SessionStatus.FINISHED
_uploadProgress.postValue(
@@ -307,6 +310,7 @@ class PeerToPeerViewModel @Inject constructor(
}
}
+
override fun onCleared() {
super.onCleared()
p2PState.clear()
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
index 2f3f2b445..6aaa6c1b3 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/uwazi/widgets/PeerToPeerEndView.java
@@ -70,7 +70,7 @@ public void setUploadProgress(List progressFiles, float pct) {
? file.getVaultFile().id
: file.getFile().getId();
- if (file.getStatus() == P2PFileStatus.FINISHED) {
+ if (isUploadedStatus(file.getStatus())) {
SubmittingItem item = partsListView.findViewWithTag(tagId);
if (item != null) item.setPartUploaded();
}
@@ -88,7 +88,7 @@ public void clearPartsProgress(List progressFiles, SessionStatus s
SubmittingItem item = partsListView.findViewWithTag(tagId);
if (item != null) {
- if (sessionStatus == SessionStatus.FINISHED || file.getStatus() == P2PFileStatus.FINISHED) {
+ if (sessionStatus == SessionStatus.FINISHED || isUploadedStatus(file.getStatus())) {
item.setPartUploaded();
} else {
item.setPartCleared();
@@ -174,21 +174,20 @@ private View createProgressFileItemView(@NonNull ProgressFile file, boolean offl
.into(thumbView);
}
- switch (file.getStatus()) {
- case FINISHED:
+ if (isUploadedStatus(file.getStatus())) {
+ item.setPartUploaded();
+ } else {
+ if (previewUploaded) {
item.setPartUploaded();
- break;
- case FAILED:
- case QUEUE:
- case SENDING:
- if (previewUploaded) {
- item.setPartUploaded();
- } else {
- item.setPartPrepared(offline);
- }
- break;
+ } else {
+ item.setPartPrepared(offline);
+ }
}
return item;
}
+
+ private boolean isUploadedStatus(P2PFileStatus status) {
+ return status == P2PFileStatus.FINISHED || status == P2PFileStatus.SAVED;
+ }
}
diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt
index 36b117ea0..657fd4e05 100644
--- a/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt
+++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/fragment/vault/adapters/connections/ServerViewHolder.kt
@@ -103,7 +103,7 @@ class ServerViewHolder(val view: View) : BaseViewHolder(view) {
reportTypeImg.setImageDrawable(
ResourcesCompat.getDrawable(
view.resources,
- R.drawable.ic_share,
+ R.drawable.ic_p2p,
null
)
)
diff --git a/mobile/src/main/res/drawable/ic_p2p.xml b/mobile/src/main/res/drawable/ic_p2p.xml
new file mode 100644
index 000000000..69ed0f6f2
--- /dev/null
+++ b/mobile/src/main/res/drawable/ic_p2p.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
diff --git a/mobile/src/main/res/drawable/ic_p2p_sharing.png b/mobile/src/main/res/drawable/ic_p2p_sharing.png
new file mode 100644
index 0000000000000000000000000000000000000000..d827a7ec519a86a2b412ee5644e4e8838ec46eba
GIT binary patch
literal 1539
zcmV+e2K@PnP)(}qK08l6t3WY+UP$(3Uz+j2Ee!o><
zjMee3P1aq_Zx7A6t9k){V7-?I7{WMH=sefrv*3^TD7f16z~+^
zW;n2NyP{{D&(g3&V7FTv71C+b?{PQpw<{drz$v4MN9!e{GddM45!ek!t!Lxcr@L~y
zu4nFUyJz@TpEyY=yLVBYthZDmB35@soA^}4*6**hyZ^fle5(z2aOeO_?QZV(Rl5FdE64jQjiK!%IGDW8^P9zK0f|5&a?Ul}8n}Jt;b`EdLyV9xqx%>P
z{+(6truNeg8?Z+Lvi@p5Te@n_I>xt%c++$de}QEmG7t_OHxlvyVj?w2jjx%dJO%l?
z_TxUlfNY>umoekJ{^}1;xkA4EM7-fPIQBs<>*%|g5Cbjr6UohCy>!(r%+Q5F*JZqi
z9d8ydeErD2L_`61@Z}7m;TT1Xtwp+_5%~VUZiO=_IQz(j$rdlle$U}|bk4cT)E(Y{
z7$n&KMEQG22zvxR!=^O0mnpuReRp{Z0T6X@nxb70TXhozum>U?#Gz|`G`bGZPBIS8
zET%&v@Vo(J77Onu+5;My5)DFv=Q8nS7sWKFoPBrIyso`IVhnykJNafa;9NTBmzP~G
zN*x5jV+(F~XHH#Bf;;6!F5qQj*Vi=~m?r1U4x%lQgeXAt971?^%8Lqa`B@(h2b0lJ?b5*W2Vwg3!8mVDu_nHLf^NF%{&?8}5Kn?W
zBKocTE&7cH>%%9$!VMaL<{cv{;zw}Vg#hSa*}8?qcCyPsju92H?YId+AzK83#59-%
z=DBreVb>~3mMxwb2}(o>B+;EI!DCF6=Z$;@$U}#Sh+RZG2ypJBo(Xei6+!Xv6Q!ZL
zvjmig5{SGzTe;hZIwRYc{^o<9e6OE#-rqj#bH*~8dzU3hm`GdVP{3jCmhDjfg7>?P
zR_(P8A)u@s1_;{2dyz!oeaFZ|90|xLLhqb?*eG5Y5CWRV()`vbV`RFJw2+aA
z=qX^pZ1Vo*WcwiOOvO#B@=Bw%gnsLLB=B{J6E1ND
zL{da4qUgYq36pSg(ZSfE=V0Uhj=0t_21QiF9eb030Up6uTfnw!_d-6rq~eJZP$Eh|
zi6{Y4n@ICx(RJ2jODph#5Eb!rh~>t@(>`*wU;%k<%SaY-A(W_1)IgjycwzW$iKeTp
zOH78F@XYc1Fc3vv$nlM0{j}#3RWqFJQxK=%D(6L)2MR-TO)j7EobS`zl_3N?!nw0=
zn`r-P>mX;55iMe(=Sj-&0thrZJBy6$?k(K47d4O|ija$AM_uIQOMJqu5Zpfy950VR
z+VwB=zjWczJsxagLs$n%Ec)E}7^2|_mI*!`RgcUg5an6?hbC@4&{zQRXQRpfku5!s
p-8WPy6bgkxp-?Ck3WY)eUjfq!132>aF@pdA002ovPDHLkV1gdd%H{w7
literal 0
HcmV?d00001
diff --git a/mobile/src/main/res/layout/connect_hotspot_layout.xml b/mobile/src/main/res/layout/connect_hotspot_layout.xml
index 171c2009e..40dd27594 100644
--- a/mobile/src/main/res/layout/connect_hotspot_layout.xml
+++ b/mobile/src/main/res/layout/connect_hotspot_layout.xml
@@ -115,13 +115,6 @@
app:leftText="@string/same_wifi_text" />
-
-
-
+ app:text="@string/send_files"
+ app:text_all_caps="true"
+ app:text_round_bold="true" />
Attach file
%1$s successfully submitted
Connect to device
- Show this QR code for the sender to scan
+ Show this QR code for the\n sender to scan
Scan the recipient’s QR code
Having trouble with the QR code?
Connect manually
diff --git a/mobile/src/main/res/values/styles.xml b/mobile/src/main/res/values/styles.xml
index 40583fcd0..b701d9e9f 100644
--- a/mobile/src/main/res/values/styles.xml
+++ b/mobile/src/main/res/values/styles.xml
@@ -427,9 +427,6 @@
- @color/wa_white
- 40sp
-