Add Cryptomator variants screen

This commit is contained in:
Julian Raufelder 2022-05-20 14:36:09 +02:00
parent 7ad0178e8b
commit fa8a9cac27
No known key found for this signature in database
GPG Key ID: 17EE71F6634E381D
19 changed files with 583 additions and 2 deletions

View File

@ -91,6 +91,9 @@ android {
fdroidmain {
dimension "version"
applicationIdSuffix ".lite"
resValue "string", "app_id", androidApplicationId + applicationIdSuffix
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.cryptomator.presentation">
<!-- Required to send intent to F-Droid app -->
<queries>
<package android:name="org.fdroid.fdroid" />
</queries>
<!-- Required to self update Cryptomator in the F-Droid main variant -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
</manifest>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- # app -->
<string name="app_name" translatable="false">Cryptomator Lite</string>
</resources>

View File

@ -119,6 +119,9 @@
<activity
android:name=".ui.activity.CloudSettingsActivity"
android:exported="false" />
<activity
android:name=".ui.activity.CryptomatorVariantsActivity"
android:exported="false" />
<activity
android:name=".ui.activity.LicensesActivity"
android:exported="true" />

View File

@ -13,6 +13,7 @@ import org.cryptomator.presentation.ui.activity.ChooseCloudServiceActivity;
import org.cryptomator.presentation.ui.activity.CloudConnectionListActivity;
import org.cryptomator.presentation.ui.activity.CloudSettingsActivity;
import org.cryptomator.presentation.ui.activity.CreateVaultActivity;
import org.cryptomator.presentation.ui.activity.CryptomatorVariantsActivity;
import org.cryptomator.presentation.ui.activity.ImagePreviewActivity;
import org.cryptomator.presentation.ui.activity.LicenseCheckActivity;
import org.cryptomator.presentation.ui.activity.LicensesActivity;
@ -123,4 +124,7 @@ public interface ActivityComponent {
void inject(S3AddOrChangeActivity s3AddOrChangeActivity);
void inject(S3AddOrChangeFragment s3AddOrChangeFragment);
void inject(CryptomatorVariantsActivity cryptomatorVariantsActivity);
}

View File

@ -0,0 +1,9 @@
package org.cryptomator.presentation.intent;
import org.cryptomator.generator.Intent;
import org.cryptomator.presentation.ui.activity.CryptomatorVariantsActivity;
@Intent(CryptomatorVariantsActivity.class)
public interface CryptomatorVariantsIntent {
}

View File

@ -1,5 +1,6 @@
package org.cryptomator.presentation.presenter
import android.view.View
import org.cryptomator.domain.Cloud
import org.cryptomator.domain.di.PerView
import org.cryptomator.domain.exception.FatalBackendException
@ -12,6 +13,7 @@ import org.cryptomator.presentation.intent.Intents
import org.cryptomator.presentation.model.CloudTypeModel
import org.cryptomator.presentation.model.mappers.CloudModelMapper
import org.cryptomator.presentation.ui.activity.view.ChooseCloudServiceView
import org.cryptomator.presentation.ui.snackbar.SnackbarAction
import org.cryptomator.presentation.workflow.ActivityResult
import org.cryptomator.presentation.workflow.AddExistingVaultWorkflow
import org.cryptomator.presentation.workflow.CreateNewVaultWorkflow
@ -92,6 +94,18 @@ class ChooseCloudServicePresenter @Inject constructor( //
finishWithResult(cloudModelMapper.toModel(cloud))
}
fun showCloudMissingSnackbarHintInFDroidMainVariant() {
if (BuildConfig.FLAVOR == "fdroidmain") {
view?.showSnackbar(R.string.snack_bar_cryptomator_variants_hint, object: SnackbarAction {
override fun onClick(v: View?) {
startIntent(Intents.cryptomatorVariantsIntent())
}
override val text: Int
get() = R.string.snack_bar_cryptomator_variants_title
})
}
}
init {
unsubscribeOnDestroy(getCloudsUseCase)
}

View File

@ -0,0 +1,103 @@
package org.cryptomator.presentation.presenter
import android.content.Intent
import android.net.Uri
import android.widget.Toast
import com.google.common.base.Optional
import org.cryptomator.data.util.NetworkConnectionCheck
import org.cryptomator.domain.di.PerView
import org.cryptomator.domain.usecases.DoUpdateCheckUseCase
import org.cryptomator.domain.usecases.DoUpdateUseCase
import org.cryptomator.domain.usecases.NoOpResultHandler
import org.cryptomator.domain.usecases.UpdateCheck
import org.cryptomator.presentation.R
import org.cryptomator.presentation.exception.ExceptionHandlers
import org.cryptomator.presentation.model.ProgressModel
import org.cryptomator.presentation.ui.activity.view.CryptomatorVariantsView
import org.cryptomator.presentation.util.FileUtil
import javax.inject.Inject
@PerView
class CryptomatorVariantsPresenter @Inject constructor(
//
exceptionMappings: ExceptionHandlers, //
private val updateCheckUseCase: DoUpdateCheckUseCase, //
private val updateUseCase: DoUpdateUseCase, //
private val networkConnectionCheck: NetworkConnectionCheck, //
private val fileUtil: FileUtil, //
) : Presenter<CryptomatorVariantsView>(exceptionMappings) {
private val fDroidPackageName = "org.fdroid.fdroid"
fun onInstallMainFDroidVariantClicked() {
context().packageManager.getLaunchIntentForPackage(fDroidPackageName)?.let {
it.data = Uri.parse("https://f-droid.org/packages/org.cryptomator.light")
context().startActivity(it)
} ?: Toast.makeText(context(), R.string.error_interact_with_fdroid_but_fdroid_missing, Toast.LENGTH_SHORT).show()
}
fun onAddRepoClicked() {
context().packageManager.getLaunchIntentForPackage(fDroidPackageName)?.let {
it.data = Uri.parse("https://static.cryptomator.org/android/fdroid/repo?fingerprint=F7C3EC3B0D588D3CB52983E9EB1A7421C93D4339A286398E71D7B651E8D8ECDD")
context().startActivity(it)
} ?: Toast.makeText(context(), R.string.error_interact_with_fdroid_but_fdroid_missing, Toast.LENGTH_SHORT).show()
}
fun onInstallFDroidVariantClicked() {
context().packageManager.getLaunchIntentForPackage(fDroidPackageName)?.let {
it.data = Uri.parse("https://f-droid.org/packages/org.cryptomator")
context().startActivity(it)
} ?: Toast.makeText(context(), R.string.error_interact_with_fdroid_but_fdroid_missing, Toast.LENGTH_SHORT).show()
}
fun onInstallWebsiteVariantClicked() {
if (networkConnectionCheck.isPresent) {
view?.showProgress(ProgressModel.GENERIC)
updateCheckUseCase //
.withVersion("0.0.0")
.run(object : NoOpResultHandler<Optional<UpdateCheck>>() {
override fun onSuccess(result: Optional<UpdateCheck>) {
installUpdate()
}
override fun onError(e: Throwable) {
view?.showProgress(ProgressModel.COMPLETED)
showError(e)
}
})
} else {
Toast.makeText(context(), R.string.error_update_no_internet, Toast.LENGTH_SHORT).show()
}
}
private fun installUpdate() {
val uri = fileUtil.contentUriForNewTempFile("cryptomator.apk")
val file = fileUtil.tempFile("cryptomator.apk")
updateUseCase //
.withFile(file) //
.run(object : NoOpResultHandler<Void?>() {
override fun onError(e: Throwable) {
showError(e)
}
override fun onSuccess(result: Void?) {
super.onSuccess(result)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context().startActivity(intent)
}
override fun onFinished() {
view?.showProgress(ProgressModel.COMPLETED)
}
})
}
init {
unsubscribeOnDestroy(updateCheckUseCase, updateUseCase)
}
}

View File

@ -316,6 +316,7 @@ abstract class BaseActivity : AppCompatActivity(), View, ActivityCompat.OnReques
internal open fun snackbarView(): android.view.View {
return activity().findViewById(R.id.locationsRecyclerView) as android.view.View?
?: activity().findViewById(R.id.rlChooseCloudService) as android.view.View?
?: return activity().findViewById(R.id.coordinatorLayout)
}

View File

@ -0,0 +1,51 @@
package org.cryptomator.presentation.ui.activity
import org.cryptomator.generator.Activity
import org.cryptomator.presentation.R
import org.cryptomator.presentation.presenter.CryptomatorVariantsPresenter
import org.cryptomator.presentation.ui.activity.view.CryptomatorVariantsView
import javax.inject.Inject
import kotlinx.android.synthetic.main.activity_cryptomator_variants.btnAddRepo
import kotlinx.android.synthetic.main.activity_cryptomator_variants.btnInstallFDroidVariant
import kotlinx.android.synthetic.main.activity_cryptomator_variants.btnInstallMainFDroidVariant
import kotlinx.android.synthetic.main.activity_cryptomator_variants.btnInstallWebsiteVariant
import kotlinx.android.synthetic.main.activity_cryptomator_variants.tvFdroidCustomSupported
import kotlinx.android.synthetic.main.activity_cryptomator_variants.tvFdroidCustomUnsupported
import kotlinx.android.synthetic.main.activity_cryptomator_variants.tvFdroidMainSupported
import kotlinx.android.synthetic.main.activity_cryptomator_variants.tvFdroidMainUnsupported
import kotlinx.android.synthetic.main.activity_cryptomator_variants.tvWebsiteAllowed
import kotlinx.android.synthetic.main.toolbar_layout.toolbar
@Activity(layout = R.layout.activity_cryptomator_variants)
class CryptomatorVariantsActivity : BaseActivity(), CryptomatorVariantsView {
@Inject
lateinit var presenter: CryptomatorVariantsPresenter
override fun setupView() {
toolbar.title = getString(R.string.screen_cryptomator_variants_title)
setSupportActionBar(toolbar)
tvFdroidMainSupported.text = "WebDAV, S3, Local Storage"
tvFdroidMainUnsupported.text = "Dropbox, Google Drive, OneDrive, pCloud"
tvFdroidCustomSupported.text = "Dropbox, OneDrive, pCloud, WebDAV, S3, Local Storage"
tvFdroidCustomUnsupported.text = "Google Drive"
tvWebsiteAllowed.text = "Dropbox, Google Drive, OneDrive, pCloud, WebDAV, S3, Local Storage"
btnInstallMainFDroidVariant.setOnClickListener {
presenter.onInstallMainFDroidVariantClicked()
}
btnAddRepo.setOnClickListener {
presenter.onAddRepoClicked()
}
btnInstallFDroidVariant.setOnClickListener {
presenter.onInstallFDroidVariantClicked()
}
btnInstallWebsiteVariant.setOnClickListener {
presenter.onInstallWebsiteVariantClicked()
}
}
}

View File

@ -0,0 +1,3 @@
package org.cryptomator.presentation.ui.activity.view
interface CryptomatorVariantsView : View

View File

@ -27,6 +27,7 @@ class ChooseCloudServiceFragment : BaseFragment() {
override fun setupView() {
setupRecyclerView()
chooseCloudServicePresenter.showCloudMissingSnackbarHintInFDroidMainVariant()
}
fun render(cloudModels: List<CloudTypeModel>?) {

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#757575"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#757575"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
</vector>

View File

@ -0,0 +1,314 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
layout="@layout/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_vertical_margin">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/tvHint">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- <website> -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp">
<TextView
android:id="@+id/tvWebsiteTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/screen_cryptomator_variants_website_title"
android:textColor="@color/colorPrimary"
android:textSize="16sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tvWebsiteTitle"
android:layout_toLeftOf="@id/btnInstallWebsiteVariant"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:foreground="@drawable/item_browse_files_node_selector">
<ImageView
android:id="@+id/supportedWebsiteIcon"
android:layout_width="@dimen/thumbnail_size"
android:layout_height="@dimen/thumbnail_size"
android:src="@drawable/ic_done_gray" />
<TextView
android:id="@+id/tvWebsiteAllowed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/supportedWebsiteIcon" />
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/screen_cryptomator_variants_website_description" />
</LinearLayout>
<Button
android:id="@+id/btnInstallWebsiteVariant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/primary_button_selector"
android:text="@string/screen_cryptomator_variants_website_install"
android:textColor="@color/textColorWhite" />
</RelativeLayout>
<!-- </website> -->
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@color/list_divider" />
<!-- <f-droid-main> -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/global_padding"
android:paddingBottom="16dp">
<TextView
android:id="@+id/tvFdroidMainTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/screen_cryptomator_variants_fdroid_main_title"
android:textColor="@color/colorPrimary"
android:textSize="16sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tvFdroidMainTitle"
android:layout_toLeftOf="@id/btnInstallMainFDroidVariant"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:foreground="@drawable/item_browse_files_node_selector">
<ImageView
android:id="@+id/supportedMainRepoIcon"
android:layout_width="@dimen/thumbnail_size"
android:layout_height="@dimen/thumbnail_size"
android:src="@drawable/ic_done_gray" />
<TextView
android:id="@+id/tvFdroidMainSupported"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/supportedMainRepoIcon" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:foreground="@drawable/item_browse_files_node_selector">
<ImageView
android:id="@+id/unsupportedMainRepoIcon"
android:layout_width="@dimen/thumbnail_size"
android:layout_height="@dimen/thumbnail_size"
android:src="@drawable/ic_clear_gray" />
<TextView
android:id="@+id/tvFdroidMainUnsupported"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/unsupportedMainRepoIcon"/>
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/screen_cryptomator_variants_website_description" />
</LinearLayout>
<Button
android:id="@+id/btnInstallMainFDroidVariant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/primary_button_selector"
android:text="@string/screen_cryptomator_variants_fdroid_main_install"
android:textColor="@color/textColorWhite" />
</RelativeLayout>
<!-- </f-droid-main> -->
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@color/list_divider" />
<!-- <f-droid-custom> -->
<TextView
android:id="@+id/tvFdroidTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/global_padding"
android:text="@string/screen_cryptomator_variants_fdroid_title"
android:textColor="@color/colorPrimary"
android:textSize="16sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:foreground="@drawable/item_browse_files_node_selector">
<ImageView
android:id="@+id/supportedMainCloudsIcon"
android:layout_width="@dimen/thumbnail_size"
android:layout_height="@dimen/thumbnail_size"
android:src="@drawable/ic_done_gray" />
<TextView
android:id="@+id/tvFdroidCustomSupported"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/supportedMainCloudsIcon" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:foreground="@drawable/item_browse_files_node_selector">
<ImageView
android:id="@+id/unsupportedCustomRepoIcon"
android:layout_width="@dimen/thumbnail_size"
android:layout_height="@dimen/thumbnail_size"
android:src="@drawable/ic_clear_gray" />
<TextView
android:id="@+id/tvFdroidCustomUnsupported"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/unsupportedCustomRepoIcon" />
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:text="@string/screen_cryptomator_variants_fdroid_description" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<TextView
android:id="@+id/tvAddRepo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/btnAddRepo"
android:text="@string/screen_cryptomator_variants_fdroid_add_repo_hint" />
<Button
android:id="@+id/btnAddRepo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@drawable/primary_button_selector"
android:text="@string/screen_cryptomator_variants_fdroid_add_repo"
android:textColor="@color/textColorWhite" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:background="?android:attr/selectableItemBackground"
android:foreground="@drawable/item_browse_files_node_selector">
<TextView
android:id="@+id/tvAskInstallApp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/btnInstallFDroidVariant"
android:text="@string/screen_cryptomator_variants_fdroid_install_hint" />
<Button
android:id="@+id/btnInstallFDroidVariant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@drawable/primary_button_selector"
android:text="@string/screen_cryptomator_variants_fdroid_install"
android:textColor="@color/textColorWhite" />
</RelativeLayout>
<!-- </f-droid-custom> -->
</LinearLayout>
</ScrollView>
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_above="@+id/tvHint"
android:background="@color/list_divider" />
<TextView
android:id="@+id/tvHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/screen_cryptomator_variants_installation_hint" />
</RelativeLayout>
</LinearLayout>

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:id="@+id/rlChooseCloudService">
<include layout="@layout/recycler_view_layout" />

View File

@ -42,6 +42,7 @@
<string name="error_file_not_found_after_opening_using_3party">Local file isn\'t present anymore after switching back to Cryptomator. Possible changes cannot be propagated back to the cloud.</string>
<string name="error_no_such_bucket">No such bucket</string>
<string name="error_masterkey_location_not_supported">Custom Masterkey location not supported yet</string>
<string name="error_interact_with_fdroid_but_fdroid_missing">Failed to communicate with the F-Droid app. Not installed?</string>
<!-- # clouds -->
@ -79,6 +80,9 @@
<string name="snack_bar_action_title_save" translatable="false">@string/screen_share_files_save_button_text</string>
<string name="snack_bar_cryptomator_variants_title">READ MORE</string>
<string name="snack_bar_cryptomator_variants_hint">Cloud not in the list?</string>
<!-- # screens -->
<!-- # screen: vault list -->
@ -300,7 +304,21 @@
<string name="screen_authenticate_auth_authentication_failed">%1$s could not be authenticated.</string>
<string name="screen_update_pcloud_connections_title">Update pCloud credentials</string>
<!-- ## screen: insecure android version info -->
<!-- ## screen: cryptomator app variants -->
<string name="screen_cryptomator_variants_title">Variants of Cryptomator</string>
<string name="screen_cryptomator_variants_fdroid_main_title">Main F-Droid Repository</string>
<string name="screen_cryptomator_variants_fdroid_main_description">Excluded because they require API keys.</string>
<string name="screen_cryptomator_variants_fdroid_main_install">Install</string>
<string name="screen_cryptomator_variants_fdroid_title">Cryptomator F-Droid Repository</string>
<string name="screen_cryptomator_variants_fdroid_description">Excluded because it contains proprietary dependencies.</string>
<string name="screen_cryptomator_variants_fdroid_add_repo_hint">Add Cryptomator repository to the F-Droid app.</string>
<string name="screen_cryptomator_variants_fdroid_add_repo">Add</string>
<string name="screen_cryptomator_variants_fdroid_install_hint">Install Cryptomator using F-Droid.\nIf a not found error is displayed, wait until the F-Droid synchronisation is finished.</string>
<string name="screen_cryptomator_variants_fdroid_install" translatable="false">@string/screen_cryptomator_variants_fdroid_main_install</string>
<string name="screen_cryptomator_variants_website_title">Website</string>
<string name="screen_cryptomator_variants_website_description">Contains proprietary dependencies.</string>
<string name="screen_cryptomator_variants_website_install" translatable="false">@string/screen_cryptomator_variants_fdroid_main_install</string>
<string name="screen_cryptomator_variants_installation_hint">Switching from or to the Main F-Droid repository variant requires a fresh setup of the app.</string>
<!-- # dialogs -->
<string name="dialog_button_cancel">Cancel</string>