Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions app/src/main/java/org/permanent/permanent/network/NetworkClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import org.permanent.permanent.BuildConfig
import org.permanent.permanent.Constants
import org.permanent.permanent.PermanentApplication
Expand All @@ -41,6 +42,8 @@ import org.permanent.permanent.network.models.LegacyContact
import org.permanent.permanent.network.models.LocnVO
import org.permanent.permanent.network.models.ProfileItemsRequestContainer
import org.permanent.permanent.network.models.ResponseVO
import org.permanent.permanent.network.models.ShareLinkVO
import org.permanent.permanent.network.models.ShareLinkVOResponse
import org.permanent.permanent.network.models.Shareby_urlVO
import org.permanent.permanent.network.models.SimpleRequestContainer
import org.permanent.permanent.network.models.StorageGift
Expand Down Expand Up @@ -784,6 +787,30 @@ class NetworkClient(private var okHttpClient: OkHttpClient?, context: Context) {

fun disableTwoFactor(twoFAVO: TwoFAVO): Call<ResponseBody> = stelaAccountService.disableTwoFactor(twoFAVO)

fun getShareLink(shareTokens: List<String>?,shareLinkIds: List<String>?): Call<ShareLinkVOResponse> = stelaAccountService.getShareLink(shareTokens,shareLinkIds)

fun generateShareLink(shareLink: ShareLinkVO): Call<ResponseVO> = stelaAccountService.generateShareLink(shareLink)

fun updateShareLink(shareLink: ShareLinkVO): Call<ResponseVO> {
val json = JSONObject()

shareLink.permissionsLevel?.let { json.put("permissionsLevel", it) }
shareLink.accessRestrictions?.let { json.put("accessRestrictions", it) }
if (shareLink.expirationTimestamp == null) {
json.put("expirationTimestamp", JSONObject.NULL)
} else {
json.put("expirationTimestamp", shareLink.expirationTimestamp)
}
val body = json.toString()
.toRequestBody("application/json; charset=utf-8".toMediaType())

return stelaAccountService.updateShareLink(shareLink.id, body)
}

fun deleteShareLink(shareLinkId: String): Call<ResponseVO> {
return stelaAccountService.deleteShareLink(shareLinkId)
}

fun getPaymentIntent(
accountId: Int,
accountEmail: String?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
package org.permanent.permanent.network

import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.permanent.permanent.models.Tags
import org.permanent.permanent.network.models.ResponseVO
import org.permanent.permanent.network.models.ShareLinkVO
import org.permanent.permanent.network.models.ShareLinkVOResponse
import org.permanent.permanent.network.models.TwoFAVO
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query

interface StelaAccountService {

@GET("api/v2/share-links")
fun getShareLink(@Query("shareTokens[]") shareTokens: List<String>?,
@Query("shareLinkIds[]") shareLinkIds: List<String>?
): Call<ShareLinkVOResponse>

@POST("api/v2/share-links")
fun generateShareLink(@Body shareLink: ShareLinkVO): Call<ResponseVO>

@PATCH("api/v2/share-links/{shareLinkId}")
fun updateShareLink(@Path("shareLinkId") shareLinkId: String?, @Body body: RequestBody): Call<ResponseVO>

@DELETE("api/v2/share-links/{shareLinkId}")
fun deleteShareLink(@Path("shareLinkId") shareLinkId: String?): Call<ResponseVO>

@PUT("api/v2/account/tags")
fun addRemoveTags(@Body tags: Tags): Call<ResponseVO>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ class Datum {
var TagVO: TagVO? = null
var TagLinkVO: TagLinkVO? = null
var PromoVO: PromoVO? = null
var ShareLinkVO: ShareLinkVO? = null

}
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,8 @@ class ResponseVO {
fun getPromoVO(): PromoVO? {
return getData()?.get(0)?.PromoVO
}

fun getShareLinkVO(): ShareLinkVO? {
return getData()?.get(0)?.ShareLinkVO
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.permanent.permanent.network.models


data class ShareLinkVOResponse(
val items: List<ShareLinkVO>
)

data class ShareLinkVO (
var id: String? = null,
var itemId: String? = null,
var itemType: String? = null,
var permissionsLevel: String? = null,
var accessRestrictions: String? = null,

var token: String? = null,

var maxUses: Int? = null, // can be 0 for unlimited uses

var usesExpended: Int? = null,
var expirationTimestamp: String? = null, // can be null for no expiration, or this format: "2026-11-17 13:56:31"

var createdAt: String? = null,
var updatedAt: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.permanent.permanent.repositories
import org.permanent.permanent.models.Tags
import org.permanent.permanent.network.IResponseListener
import org.permanent.permanent.network.ITwoFAListener
import org.permanent.permanent.network.models.ShareLinkVO
import org.permanent.permanent.network.models.TwoFAVO

interface StelaAccountRepository {
Expand All @@ -18,4 +19,12 @@ interface StelaAccountRepository {
fun sendDisableCode(twoFAVO: TwoFAVO, listener: IResponseListener)

fun disableTwoFactor(twoFAVO: TwoFAVO, listener: IResponseListener)

fun getShareLink(shareTokens: List<String>?,shareLinkIds: List<String>?, listener: IResponseListener)

fun generateShareLink(shareLinkVO: ShareLinkVO, listener: IResponseListener)

fun updateShareLink(shareLinkVO: ShareLinkVO, listener: IResponseListener)

fun deleteShareLink(shareLinkId: String, listener: IResponseListener)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import org.permanent.permanent.network.ITwoFAListener
import org.permanent.permanent.network.NetworkClient
import org.permanent.permanent.network.models.ErrorResponse
import org.permanent.permanent.network.models.ResponseVO
import org.permanent.permanent.network.models.ShareLinkVO
import org.permanent.permanent.network.models.ShareLinkVOResponse
import org.permanent.permanent.network.models.TwoFAVO
import retrofit2.Call
import retrofit2.Callback
Expand Down Expand Up @@ -192,4 +194,97 @@ class StelaAccountRepositoryImpl(context: Context) : StelaAccountRepository {
}
})
}

override fun getShareLink(shareTokens: List<String>?,shareLinkIds: List<String>?, listener: IResponseListener) {
NetworkClient.instance().getShareLink(shareTokens, shareLinkIds).enqueue( object : Callback<ShareLinkVOResponse> {

override fun onResponse(call: Call<ShareLinkVOResponse>, response: Response<ShareLinkVOResponse>) {
if (response.isSuccessful) {
val responseVO = response.body()
if (responseVO != null) {
listener.onSuccess("")
} else {
listener.onFailed(appContext.getString(R.string.generic_error))
}
} else {
listener.onFailed("No Link detected")
}
}

override fun onFailure(call: Call<ShareLinkVOResponse>, t: Throwable) {
listener.onFailed(t.message)
}
})
}

override fun generateShareLink(shareLinkVO: ShareLinkVO, listener: IResponseListener) {
NetworkClient.instance().generateShareLink(shareLinkVO).enqueue( object : Callback<ResponseVO> {

override fun onResponse(call: Call<ResponseVO>, response: Response<ResponseVO>) {
if (response.isSuccessful) {
val responseVO = response.body()
if (responseVO != null) {
listener.onSuccess("")
} else {
listener.onFailed(appContext.getString(R.string.generic_error))
}
} else {
listener.onFailed("No Link detected")
}
}

override fun onFailure(call: Call<ResponseVO>, t: Throwable) {
listener.onFailed(t.message)
}
})
}

override fun updateShareLink(shareLinkVO: ShareLinkVO, listener: IResponseListener) {
NetworkClient.instance().updateShareLink(shareLinkVO)
.enqueue(object : Callback<ResponseVO> {

override fun onResponse(call: Call<ResponseVO>, response: Response<ResponseVO>) {
if (response.isSuccessful) {
val responseVO = response.body()
if (responseVO != null) {
listener.onSuccess("")
} else {
listener.onFailed(appContext.getString(R.string.generic_error))
}
} else {
try {
listener.onFailed(response.errorBody().toString())
} catch (e: Exception) {
listener.onFailed(e.message)
}
}
}

override fun onFailure(call: Call<ResponseVO>, t: Throwable) {
listener.onFailed(t.message)
}
})
}

override fun deleteShareLink(shareLinkId: String, listener: IResponseListener) {
NetworkClient.instance().deleteShareLink(shareLinkId)
.enqueue(object : Callback<ResponseVO> {

override fun onResponse(call: Call<ResponseVO>, response: Response<ResponseVO>) {
if (response.isSuccessful) {
listener.onSuccess("")
} else {
try {
listener.onFailed(response.errorBody().toString())
} catch (e: Exception) {
listener.onFailed(e.message)
}
}
}

override fun onFailure(call: Call<ResponseVO>, t: Throwable) {
listener.onFailed(t.message)
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import org.permanent.permanent.databinding.FragmentAccessRolesBinding
import org.permanent.permanent.models.AccessRole
import org.permanent.permanent.models.Share
import org.permanent.permanent.network.models.Shareby_urlVO
import org.permanent.permanent.ui.shareManagement.ShareManagementFragment
import org.permanent.permanent.viewmodels.AccessRolesViewModel
import org.permanent.permanent.viewmodels.SingleLiveEvent
import androidx.core.net.toUri
import org.permanent.permanent.ui.shareManagement.ShareLinkFragment

class AccessRolesFragment : PermanentBottomSheetFragment() {
private lateinit var binding: FragmentAccessRolesBinding
Expand All @@ -38,15 +38,15 @@ class AccessRolesFragment : PermanentBottomSheetFragment() {
shareByUrlVo: Shareby_urlVO,
) {
val bundle = Bundle()
bundle.putParcelable(ShareManagementFragment.SHARE_BY_URL_VO_KEY, shareByUrlVo)
bundle.putParcelable(ShareLinkFragment.SHARE_BY_URL_VO_KEY, shareByUrlVo)
this.arguments = bundle
}

fun setBundleArguments(
share: Share,
) {
val bundle = Bundle()
bundle.putParcelable(ShareManagementFragment.PARCELABLE_SHARE_KEY, share)
bundle.putParcelable(ShareLinkFragment.PARCELABLE_SHARE_KEY, share)
this.arguments = bundle
}

Expand All @@ -60,8 +60,8 @@ class AccessRolesFragment : PermanentBottomSheetFragment() {
binding.executePendingBindings()
binding.lifecycleOwner = this
binding.viewModel = viewModel
viewModel.setShareLink(arguments?.getParcelable(ShareManagementFragment.SHARE_BY_URL_VO_KEY))
viewModel.setShare(arguments?.getParcelable(ShareManagementFragment.PARCELABLE_SHARE_KEY))
viewModel.setShareLink(arguments?.getParcelable(ShareLinkFragment.SHARE_BY_URL_VO_KEY))
viewModel.setShare(arguments?.getParcelable(ShareLinkFragment.PARCELABLE_SHARE_KEY))
initCurrentAccessRole()

return binding.root
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/org/permanent/permanent/ui/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
import java.util.Date
import java.util.Locale
Expand Down Expand Up @@ -117,6 +119,21 @@ fun bytesToCustomHumanReadableString(bytes: Long, showDecimal: Boolean): String
}.toString()
}

private val BACKEND_DATE_TIME_FORMATTER: DateTimeFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

/**
* Convert a LocalDate to a backend datetime string.
*
* @param useEndOfDay if true, result will be at 23:59:59 of the date (default = true).
* if false, result will be at 00:00:00 of the date.
*/
fun LocalDate.toBackendDateTimeString(useEndOfDay: Boolean = true): String? {
val time = if (useEndOfDay) LocalTime.of(23, 59, 59) else LocalTime.MIDNIGHT
val dt = LocalDateTime.of(this, time)
return dt.format(BACKEND_DATE_TIME_FORMATTER)
}

fun String?.toDisplayDate(): String {
if (this.isNullOrBlank()) return ""
return try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fun AnimatedSnackbar(
.fillMaxWidth()
.border(1.dp, colorResource(id = if (isForError) R.color.errorLight else R.color.success200), RoundedCornerShape(12.dp))
.background(
color = colorResource(id = if (isForError) R.color.errorSuperLight else R.color.successLight),
color = colorResource(id = if (isForError) R.color.errorSuperLight else R.color.success50),
shape = RoundedCornerShape(size = 12.dp)
), contentAlignment = Alignment.Center
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ import androidx.compose.ui.res.painterResource
import org.permanent.permanent.R

@Composable
fun CircularProgressIndicator(overlayColor: OverlayColor = OverlayColor.DARK) {
fun CircularProgressIndicator(overlayColor: OverlayColor = OverlayColor.DARK, modifier: Modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.fillMaxSize()
modifier = modifier
.background(if (overlayColor == OverlayColor.DARK) Color.Black.copy(alpha = 0.5f) else Color.White.copy(alpha = 0.5f))
.clickable(enabled = false) {}, contentAlignment = Alignment.Center
) {
Expand Down
Loading