mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-10-15 15:59:18 +00:00
Improve homepage URL launching (#632)
* Move homepage and other Web URLs to Constants; minor refactoring * Use AppTheme with built-in safe LocalUriHandler instead of MdcTheme; minor refactoring * Account settings: add TODO for Compose rewrite * Use UriHandler instead of UiUtils.launch when possible
This commit is contained in:
parent
af5c732adc
commit
377c0344da
|
@ -5,11 +5,7 @@
|
|||
package at.bitfire.davdroid
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.StrictMode
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.hilt.work.HiltWorkerFactory
|
||||
import androidx.work.Configuration
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
|
@ -27,37 +23,6 @@ import kotlin.system.exitProcess
|
|||
@HiltAndroidApp
|
||||
class App: Application(), Thread.UncaughtExceptionHandler, Configuration.Provider {
|
||||
|
||||
companion object {
|
||||
|
||||
const val HOMEPAGE_PRIVACY = "privacy"
|
||||
|
||||
fun getLauncherBitmap(context: Context) =
|
||||
AppCompatResources.getDrawable(context, R.mipmap.ic_launcher)?.toBitmap()
|
||||
|
||||
/**
|
||||
* Gets the DAVx5 Web site URL that should be used to open in the user's browser.
|
||||
* Package ID, version number and calling context name will be appended as arguments.
|
||||
*
|
||||
* @param context context name to use
|
||||
* @param page optional page segment to append (for instance: [HOMEPAGE_PRIVACY]])
|
||||
*
|
||||
* @return the Uri for the browser
|
||||
*/
|
||||
fun homepageUrl(context: Context, page: String? = null): Uri {
|
||||
val builder = Uri.parse(context.getString(R.string.homepage_url)).buildUpon()
|
||||
|
||||
if (page != null)
|
||||
builder.appendPath(page)
|
||||
|
||||
return builder
|
||||
.appendQueryParameter("pk_campaign", BuildConfig.APPLICATION_ID)
|
||||
.appendQueryParameter("pk_kwd", context::class.java.simpleName)
|
||||
.appendQueryParameter("app-version", BuildConfig.VERSION_NAME)
|
||||
.build()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Inject lateinit var accountsUpdatedListener: AccountsUpdatedListener
|
||||
@Inject lateinit var storageLowReceiver: StorageLowReceiver
|
||||
|
||||
|
|
|
@ -3,25 +3,43 @@
|
|||
**************************************************************************************************/
|
||||
package at.bitfire.davdroid
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
|
||||
/**
|
||||
* Brand-specific constants like (non-theme) colors, homepage URLs etc.
|
||||
*/
|
||||
object Constants {
|
||||
|
||||
const val DAVDROID_GREEN_RGBA = 0xFF8bc34a.toInt()
|
||||
|
||||
// gplay billing
|
||||
const val BILLINGCLIENT_CONNECTION_MAX_RETRIES = 4
|
||||
val HOMEPAGE_URL = "https://www.davx5.com".toUri()
|
||||
const val HOMEPAGE_PATH_FAQ = "faq"
|
||||
const val HOMEPAGE_PATH_FAQ_SYNC_NOT_RUN = "synchronization-is-not-run-as-expected"
|
||||
const val HOMEPAGE_PATH_OPEN_SOURCE = "donate"
|
||||
const val HOMEPAGE_PATH_PRIVACY = "privacy"
|
||||
const val HOMEPAGE_PATH_TESTED_SERVICES = "tested-with"
|
||||
|
||||
val MANUAL_URL = "https://manual.davx5.com".toUri()
|
||||
const val MANUAL_PATH_WEBDAV_MOUNTS = "webdav_mounts.html"
|
||||
|
||||
val COMMUNITY_URL = "https://github.com/bitfireAT/davx5-ose/discussions".toUri()
|
||||
val FEDIVERSE_URL = "https://fosstodon.org/@davx5app".toUri()
|
||||
|
||||
/**
|
||||
* Context label for [org.apache.commons.lang3.exception.ContextedException].
|
||||
* Context value is the [at.bitfire.davdroid.resource.LocalResource]
|
||||
* which is related to the exception cause.
|
||||
* Appends query parameters for anonymized usage statistics (app ID, version).
|
||||
* Can be used by the called Website to get an idea of which versions etc. are currently used.
|
||||
*
|
||||
* @param context optional info about from where the URL was opened (like a specific Activity)
|
||||
*/
|
||||
const val EXCEPTION_CONTEXT_LOCAL_RESOURCE = "localResource"
|
||||
fun Uri.Builder.withStatParams(context: String? = null): Uri.Builder {
|
||||
appendQueryParameter("pk_campaign", BuildConfig.APPLICATION_ID)
|
||||
appendQueryParameter("app-version", BuildConfig.VERSION_NAME)
|
||||
|
||||
/**
|
||||
* Context label for [org.apache.commons.lang3.exception.ContextedException].
|
||||
* Context value is the [okhttp3.HttpUrl] of the remote resource
|
||||
* which is related to the exception cause.
|
||||
*/
|
||||
const val EXCEPTION_CONTEXT_REMOTE_RESOURCE = "remoteResource"
|
||||
if (context != null)
|
||||
appendQueryParameter("pk_kwd", context)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
|
@ -34,7 +34,6 @@ import at.bitfire.dav4jvm.property.caldav.GetCTag
|
|||
import at.bitfire.dav4jvm.property.caldav.ScheduleTag
|
||||
import at.bitfire.dav4jvm.property.webdav.GetETag
|
||||
import at.bitfire.dav4jvm.property.webdav.SyncToken
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.InvalidAccountException
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
|
@ -67,7 +66,6 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.RequestBody
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.apache.commons.lang3.exception.ContextedException
|
||||
import org.dmfs.tasks.contract.TaskContract
|
||||
import java.io.IOException
|
||||
|
@ -105,14 +103,28 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val DEBUG_INFO_MAX_RESOURCE_DUMP_SIZE = 100*FileUtils.ONE_KB.toInt()
|
||||
|
||||
/** Maximum number of resources that are requested with one multiget request. */
|
||||
const val MAX_MULTIGET_RESOURCES = 10
|
||||
|
||||
const val DELAY_UNTIL_DEFAULT = 15*60L // 15 min
|
||||
const val DELAY_UNTIL_MIN = 1*60L // 1 min
|
||||
const val DELAY_UNTIL_MAX = 2*60*60L // 2 hours
|
||||
|
||||
/**
|
||||
* Context label for [org.apache.commons.lang3.exception.ContextedException].
|
||||
* Context value is the [at.bitfire.davdroid.resource.LocalResource]
|
||||
* which is related to the exception cause.
|
||||
*/
|
||||
const val EXCEPTION_CONTEXT_LOCAL_RESOURCE = "localResource"
|
||||
|
||||
/**
|
||||
* Context label for [org.apache.commons.lang3.exception.ContextedException].
|
||||
* Context value is the [okhttp3.HttpUrl] of the remote resource
|
||||
* which is related to the exception cause.
|
||||
*/
|
||||
const val EXCEPTION_CONTEXT_REMOTE_RESOURCE = "remoteResource"
|
||||
|
||||
/**
|
||||
* Returns appropriate sync retry delay in seconds, considering the servers suggestion
|
||||
* ([DELAY_UNTIL_DEFAULT] if no server suggestion).
|
||||
|
@ -865,11 +877,11 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
|
|||
try {
|
||||
return body(local)
|
||||
} catch (e: ContextedException) {
|
||||
e.addContextValue(Constants.EXCEPTION_CONTEXT_LOCAL_RESOURCE, local)
|
||||
e.addContextValue(EXCEPTION_CONTEXT_LOCAL_RESOURCE, local)
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
if (local != null)
|
||||
throw ContextedException(e).setContextValue(Constants.EXCEPTION_CONTEXT_LOCAL_RESOURCE, local)
|
||||
throw ContextedException(e).setContextValue(EXCEPTION_CONTEXT_LOCAL_RESOURCE, local)
|
||||
else
|
||||
throw e
|
||||
}
|
||||
|
@ -879,10 +891,10 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
|
|||
try {
|
||||
return body(remote)
|
||||
} catch (e: ContextedException) {
|
||||
e.addContextValue(Constants.EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.location)
|
||||
e.addContextValue(EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.location)
|
||||
throw e
|
||||
} catch(e: Throwable) {
|
||||
throw ContextedException(e).setContextValue(Constants.EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.location)
|
||||
throw ContextedException(e).setContextValue(EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.location)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -890,10 +902,10 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
|
|||
try {
|
||||
return body(remote)
|
||||
} catch (e: ContextedException) {
|
||||
e.addContextValue(Constants.EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.href)
|
||||
e.addContextValue(EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.href)
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw ContextedException(e).setContextValue(Constants.EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.href)
|
||||
throw ContextedException(e).setContextValue(EXCEPTION_CONTEXT_REMOTE_RESOURCE, remote.href)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -914,12 +926,10 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
|
|||
if (ex is ContextedException) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
// we want the innermost context value, which is the first one
|
||||
(ex.getFirstContextValue(Constants.EXCEPTION_CONTEXT_LOCAL_RESOURCE) as? ResourceType)?.let {
|
||||
if (local == null)
|
||||
(ex.getFirstContextValue(EXCEPTION_CONTEXT_LOCAL_RESOURCE) as? ResourceType)?.let {
|
||||
local = it
|
||||
}
|
||||
(ex.getFirstContextValue(Constants.EXCEPTION_CONTEXT_REMOTE_RESOURCE) as? HttpUrl)?.let {
|
||||
if (remote == null)
|
||||
(ex.getFirstContextValue(EXCEPTION_CONTEXT_REMOTE_RESOURCE) as? HttpUrl)?.let {
|
||||
remote = it
|
||||
}
|
||||
ex = ex.cause
|
||||
|
|
|
@ -6,7 +6,6 @@ package at.bitfire.davdroid.ui
|
|||
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
@ -41,6 +40,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
@ -48,12 +48,12 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.BuildConfig
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.Constants.withStatParams
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.ui.widget.PixelBoxes
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import com.mikepenz.aboutlibraries.Libs
|
||||
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
|
||||
import com.mikepenz.aboutlibraries.util.withJson
|
||||
|
@ -71,7 +71,9 @@ import java.time.LocalDateTime
|
|||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.*
|
||||
import java.util.LinkedList
|
||||
import java.util.Locale
|
||||
import java.util.Optional
|
||||
import java.util.logging.Level
|
||||
import javax.inject.Inject
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
@ -90,7 +92,9 @@ class AboutActivity: AppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
AppTheme {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
|
@ -107,8 +111,10 @@ class AboutActivity: AppCompatActivity() {
|
|||
},
|
||||
actions = {
|
||||
IconButton(onClick = {
|
||||
val context = this@AboutActivity
|
||||
UiUtils.launchUri(context, App.homepageUrl(context))
|
||||
uriHandler.openUri(Constants.HOMEPAGE_URL
|
||||
.buildUpon()
|
||||
.withStatParams("AboutActivity")
|
||||
.build().toString())
|
||||
}) {
|
||||
Icon(
|
||||
Icons.Default.Home,
|
||||
|
|
|
@ -143,7 +143,7 @@ class AccountsActivity: AppCompatActivity() {
|
|||
|
||||
val accounts by model.accountInfos.observeAsState()
|
||||
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
Scaffold(
|
||||
scaffoldState = scaffoldState,
|
||||
drawerContent = drawerContent(scope, scaffoldState),
|
||||
|
|
|
@ -38,7 +38,6 @@ import androidx.compose.material.icons.filled.InvertColors
|
|||
import androidx.compose.material.icons.filled.Notifications
|
||||
import androidx.compose.material.icons.filled.SyncProblem
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -71,13 +70,11 @@ import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage
|
|||
import at.bitfire.davdroid.ui.intro.OpenSourcePage
|
||||
import at.bitfire.davdroid.ui.widget.EditTextInputDialog
|
||||
import at.bitfire.davdroid.ui.widget.MultipleChoiceInputDialog
|
||||
import at.bitfire.davdroid.ui.widget.SafeAndroidUriHandler
|
||||
import at.bitfire.davdroid.ui.widget.Setting
|
||||
import at.bitfire.davdroid.ui.widget.SettingsHeader
|
||||
import at.bitfire.davdroid.ui.widget.SwitchSetting
|
||||
import at.bitfire.davdroid.util.PermissionUtils
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -94,13 +91,11 @@ class AppSettingsActivity: AppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
CompositionLocalProvider(LocalUriHandler provides SafeAndroidUriHandler(this)) {
|
||||
AppTheme {
|
||||
AppSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("BatteryLife")
|
||||
@Composable
|
||||
|
|
|
@ -181,7 +181,7 @@ class DebugInfoActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
val debugInfo by model.debugInfo.observeAsState()
|
||||
val zipProgress by model.zipProgress.observeAsState(false)
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ class ExceptionInfoFragment: DialogFragment() {
|
|||
setContentView(
|
||||
ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
ExceptionInfoDialog(
|
||||
exception = exception,
|
||||
account = account
|
||||
|
|
|
@ -6,9 +6,12 @@ package at.bitfire.davdroid.ui
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.MenuItem
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.Constants.COMMUNITY_URL
|
||||
import at.bitfire.davdroid.Constants.FEDIVERSE_URL
|
||||
import at.bitfire.davdroid.Constants.MANUAL_URL
|
||||
import at.bitfire.davdroid.Constants.withStatParams
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.ui.webdav.WebdavMountsActivity
|
||||
import javax.inject.Inject
|
||||
|
@ -18,18 +21,16 @@ import javax.inject.Inject
|
|||
*/
|
||||
class OseAccountsDrawerHandler @Inject constructor(): BaseAccountsDrawerHandler() {
|
||||
|
||||
companion object {
|
||||
const val COMMUNITY_URL = "https://github.com/bitfireAT/davx5-ose/discussions"
|
||||
const val MANUAL_URL = "https://manual.davx5.com"
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(activity: Activity, item: MenuItem) {
|
||||
val homepageUrl = Constants.HOMEPAGE_URL.buildUpon()
|
||||
.withStatParams("OseAccountsDrawerHandler")
|
||||
|
||||
when (item.itemId) {
|
||||
|
||||
R.id.nav_mastodon ->
|
||||
UiUtils.launchUri(
|
||||
activity,
|
||||
Uri.parse("https://fosstodon.org/@davx5app")
|
||||
FEDIVERSE_URL
|
||||
)
|
||||
|
||||
R.id.nav_webdav_mounts ->
|
||||
|
@ -38,29 +39,29 @@ class OseAccountsDrawerHandler @Inject constructor(): BaseAccountsDrawerHandler(
|
|||
R.id.nav_website ->
|
||||
UiUtils.launchUri(
|
||||
activity,
|
||||
App.homepageUrl(activity)
|
||||
homepageUrl.build()
|
||||
)
|
||||
R.id.nav_manual ->
|
||||
UiUtils.launchUri(
|
||||
activity,
|
||||
Uri.parse(MANUAL_URL)
|
||||
MANUAL_URL
|
||||
)
|
||||
R.id.nav_faq ->
|
||||
UiUtils.launchUri(
|
||||
activity,
|
||||
App.homepageUrl(activity, "faq")
|
||||
homepageUrl.appendPath(Constants.HOMEPAGE_PATH_FAQ).build()
|
||||
)
|
||||
R.id.nav_community ->
|
||||
UiUtils.launchUri(activity, Uri.parse(COMMUNITY_URL))
|
||||
UiUtils.launchUri(activity, COMMUNITY_URL)
|
||||
R.id.nav_donate ->
|
||||
UiUtils.launchUri(
|
||||
activity,
|
||||
App.homepageUrl(activity, "donate")
|
||||
homepageUrl.appendPath(Constants.HOMEPAGE_PATH_OPEN_SOURCE).build()
|
||||
)
|
||||
R.id.nav_privacy ->
|
||||
UiUtils.launchUri(
|
||||
activity,
|
||||
App.homepageUrl(activity, App.HOMEPAGE_PRIVACY)
|
||||
homepageUrl.appendPath(Constants.HOMEPAGE_PATH_PRIVACY).build()
|
||||
)
|
||||
|
||||
else ->
|
||||
|
|
|
@ -61,7 +61,7 @@ class PermissionsActivity: AppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
PermissionsContent(model)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.BiasAlignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
|
@ -57,7 +58,6 @@ import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
|
|||
import at.bitfire.davdroid.ui.widget.CardWithImage
|
||||
import at.bitfire.davdroid.ui.widget.RadioWithSwitch
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -71,7 +71,7 @@ class TasksActivity: AppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
TasksCard(model = model)
|
||||
}
|
||||
}
|
||||
|
@ -268,12 +268,13 @@ fun TasksCard(
|
|||
HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||
).toAnnotatedString()
|
||||
|
||||
val uriHandler = LocalUriHandler.current
|
||||
ClickableText(
|
||||
text = summary,
|
||||
onClick = { index ->
|
||||
// Get the tapped position, and check if there's any link
|
||||
summary.getUrlAnnotations(index, index).firstOrNull()?.item?.url?.let { url ->
|
||||
UiUtils.launchUri(context, Uri.parse(url))
|
||||
uriHandler.openUri(url)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
18
app/src/main/kotlin/at/bitfire/davdroid/ui/Theme.kt
Normal file
18
app/src/main/kotlin/at/bitfire/davdroid/ui/Theme.kt
Normal file
|
@ -0,0 +1,18 @@
|
|||
package at.bitfire.davdroid.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import at.bitfire.davdroid.ui.widget.SafeAndroidUriHandler
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Composable
|
||||
fun AppTheme(content: @Composable () -> Unit) {
|
||||
CompositionLocalProvider(LocalUriHandler provides SafeAndroidUriHandler(LocalContext.current)) {
|
||||
MdcTheme {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -86,7 +86,7 @@ object UiUtils {
|
|||
* @return true on success, false if the Intent could not be resolved (for instance, because
|
||||
* there is no user agent installed)
|
||||
*/
|
||||
@Deprecated("Use SafeAndroidUriHandler (Compose) instead")
|
||||
@Deprecated("Use LocalUriHandler.open() instead (Compose)")
|
||||
fun launchUri(context: Context, uri: Uri, action: String = Intent.ACTION_VIEW, toastInstallBrowser: Boolean = true): Boolean {
|
||||
val intent = Intent(action, uri)
|
||||
try {
|
||||
|
|
|
@ -80,11 +80,11 @@ import at.bitfire.davdroid.resource.TaskUtils
|
|||
import at.bitfire.davdroid.servicedetection.RefreshCollectionsWorker
|
||||
import at.bitfire.davdroid.settings.AccountSettings
|
||||
import at.bitfire.davdroid.syncadapter.SyncWorker
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import at.bitfire.davdroid.ui.PermissionsActivity
|
||||
import at.bitfire.davdroid.ui.widget.ActionCard
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
@ -125,7 +125,7 @@ class AccountActivity2 : AppCompatActivity() {
|
|||
}
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
val cardDavSvc by model.cardDavSvc.observeAsState()
|
||||
val canCreateAddressBook by model.canCreateAddressBook.observeAsState(false)
|
||||
val cardDavRefreshing by model.cardDavRefreshingActive.observeAsState(false)
|
||||
|
|
|
@ -46,7 +46,7 @@ import at.bitfire.davdroid.db.AppDatabase
|
|||
import at.bitfire.davdroid.db.Collection
|
||||
import at.bitfire.davdroid.db.HomeSet
|
||||
import at.bitfire.davdroid.db.Service
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
@ -82,7 +82,7 @@ class CreateAddressBookActivity: AppCompatActivity() {
|
|||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
val displayName by model.displayName.observeAsState()
|
||||
val description by model.description.observeAsState()
|
||||
val homeSet by model.homeSet.observeAsState()
|
||||
|
|
|
@ -24,7 +24,12 @@ import androidx.lifecycle.MediatorLiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.preference.*
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceGroup
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import at.bitfire.davdroid.InvalidAccountException
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.db.Credentials
|
||||
|
@ -66,6 +71,7 @@ class SettingsActivity: AppCompatActivity() {
|
|||
title = getString(R.string.settings_title, account.name)
|
||||
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
// TODO add help button that leads to manual
|
||||
|
||||
if (savedInstanceState == null)
|
||||
supportFragmentManager.beginTransaction()
|
||||
|
|
|
@ -33,7 +33,6 @@ import androidx.compose.material.OutlinedButton
|
|||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
|
@ -48,15 +47,15 @@ import androidx.core.content.getSystemService
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.BuildConfig
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.Constants.withStatParams
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.settings.SettingsManager
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage.Model.Companion.HINT_AUTOSTART_PERMISSION
|
||||
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage.Model.Companion.HINT_BATTERY_OPTIMIZATIONS
|
||||
import at.bitfire.davdroid.ui.widget.SafeAndroidUriHandler
|
||||
import at.bitfire.davdroid.util.PermissionUtils
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
|
@ -112,8 +111,6 @@ class BatteryOptimizationsPage: IntroPage {
|
|||
}
|
||||
|
||||
val hintAutostartPermission by model.hintAutostartPermission.observeAsState()
|
||||
val uriHandler = SafeAndroidUriHandler(LocalContext.current)
|
||||
CompositionLocalProvider(LocalUriHandler provides uriHandler) {
|
||||
BatteryOptimizationsContent(
|
||||
dontShowBattery = hintBatteryOptimizations == false,
|
||||
onChangeDontShowBattery = {
|
||||
|
@ -129,7 +126,6 @@ class BatteryOptimizationsPage: IntroPage {
|
|||
manufacturerWarning = Model.manufacturerWarning
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@HiltViewModel
|
||||
|
@ -234,7 +230,7 @@ class BatteryOptimizationsPage: IntroPage {
|
|||
@Preview(showBackground = true, showSystemUi = true)
|
||||
@Composable
|
||||
private fun BatteryOptimizationsContent_Preview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
BatteryOptimizationsContent(
|
||||
dontShowBattery = true,
|
||||
onChangeDontShowBattery = {},
|
||||
|
@ -346,14 +342,14 @@ private fun BatteryOptimizationsContent(
|
|||
OutlinedButton(
|
||||
onClick = {
|
||||
uriHandler.openUri(
|
||||
App.homepageUrl(context)
|
||||
.buildUpon()
|
||||
.appendPath("faq")
|
||||
.appendPath("synchronization-is-not-run-as-expected")
|
||||
Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_FAQ)
|
||||
.appendPath(Constants.HOMEPAGE_PATH_FAQ_SYNC_NOT_RUN)
|
||||
.appendQueryParameter(
|
||||
"manufacturer",
|
||||
Build.MANUFACTURER.lowercase(Locale.ROOT)
|
||||
)
|
||||
.withStatParams("BatteryOptimizationsPage")
|
||||
.build().toString()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@ import androidx.fragment.app.activityViewModels
|
|||
import androidx.lifecycle.AndroidViewModel
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import com.github.appintro.AppIntro2
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
@ -112,7 +112,7 @@ class IntroActivity : AppIntro2() {
|
|||
ComposeView(requireActivity()).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
Box(Modifier.padding(bottom = dimensionResource(com.github.appintro.R.dimen.appintro2_bottombar_height))) {
|
||||
page.ComposePage()
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import androidx.compose.material.MaterialTheme
|
|||
import androidx.compose.material.OutlinedButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -27,7 +26,6 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -36,11 +34,11 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.databinding.ObservableBoolean
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.Constants.withStatParams
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.settings.SettingsManager
|
||||
import at.bitfire.davdroid.ui.widget.CardWithImage
|
||||
import at.bitfire.davdroid.ui.widget.SafeAndroidUriHandler
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
|
@ -74,8 +72,6 @@ class OpenSourcePage : IntroPage {
|
|||
private fun Page(model: Model = viewModel()) {
|
||||
var dontShow by remember { mutableStateOf(model.dontShow.get()) }
|
||||
|
||||
val uriHandler = SafeAndroidUriHandler(LocalContext.current)
|
||||
CompositionLocalProvider(LocalUriHandler provides uriHandler) {
|
||||
PageContent(
|
||||
dontShow = dontShow,
|
||||
onChangeDontShow = {
|
||||
|
@ -84,7 +80,6 @@ class OpenSourcePage : IntroPage {
|
|||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(
|
||||
showBackground = true,
|
||||
|
@ -95,7 +90,6 @@ class OpenSourcePage : IntroPage {
|
|||
dontShow: Boolean = false,
|
||||
onChangeDontShow: (Boolean) -> Unit = {}
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Column(
|
||||
|
@ -116,9 +110,9 @@ class OpenSourcePage : IntroPage {
|
|||
OutlinedButton(
|
||||
onClick = {
|
||||
uriHandler.openUri(
|
||||
App.homepageUrl(context)
|
||||
.buildUpon()
|
||||
.appendPath("donate")
|
||||
Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_OPEN_SOURCE)
|
||||
.withStatParams("OpenSourcePage")
|
||||
.build()
|
||||
.toString()
|
||||
)
|
||||
|
|
|
@ -32,8 +32,8 @@ import at.bitfire.davdroid.R
|
|||
import at.bitfire.davdroid.db.Credentials
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.servicedetection.DavResourceFinder
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import at.bitfire.davdroid.ui.DebugInfoActivity
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -80,7 +80,7 @@ class DetectConfigurationFragment: Fragment() {
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =
|
||||
ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
DetectConfigurationView()
|
||||
}
|
||||
|
||||
|
|
|
@ -33,17 +33,15 @@ import androidx.compose.material.Card
|
|||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.OutlinedTextField
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
|
@ -52,7 +50,6 @@ import androidx.compose.ui.text.input.KeyboardType
|
|||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
|
@ -60,14 +57,15 @@ import androidx.fragment.app.viewModels
|
|||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.BuildConfig
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.Constants.withStatParams
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.db.Credentials
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.ui.UiUtils
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import at.bitfire.davdroid.ui.setup.GoogleLoginFragment.Companion.URI_TESTED_WITH_GOOGLE
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
@ -95,7 +93,11 @@ class GoogleLoginFragment(private val defaultEmail: String? = null): Fragment()
|
|||
const val GOOGLE_POLICY_URL = "https://developers.google.com/terms/api-services-user-data-policy#additional_requirements_for_specific_api_scopes"
|
||||
|
||||
// Support site
|
||||
val URI_TESTED_WITH_GOOGLE: Uri = Uri.parse("https://www.davx5.com/tested-with/google")
|
||||
val URI_TESTED_WITH_GOOGLE: Uri =
|
||||
Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_TESTED_SERVICES)
|
||||
.appendPath("google")
|
||||
.build()
|
||||
|
||||
// davx5integration@gmail.com (for davx5-ose)
|
||||
private const val CLIENT_ID = "1069050168830-eg09u4tk1cmboobevhm4k3bj1m4fav9i.apps.googleusercontent.com"
|
||||
|
@ -228,7 +230,9 @@ fun GoogleLogin(
|
|||
onLogin: (accountEmail: String, clientId: String?) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
MdcTheme {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
AppTheme {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
|
@ -241,14 +245,19 @@ fun GoogleLogin(
|
|||
Card(Modifier.fillMaxWidth()) {
|
||||
Column(Modifier.padding(8.dp)) {
|
||||
Row {
|
||||
Image(Icons.Default.Warning, colorFilter = ColorFilter.tint(MaterialTheme.colors.onSurface), contentDescription = "",
|
||||
modifier = Modifier.padding(top = 8.dp, end = 8.dp, bottom = 8.dp))
|
||||
Text(stringResource(R.string.login_google_see_tested_with))
|
||||
Text(
|
||||
stringResource(R.string.login_google_see_tested_with),
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
Text(stringResource(R.string.login_google_unexpected_warnings), modifier = Modifier.padding(vertical = 8.dp))
|
||||
Text(
|
||||
stringResource(R.string.login_google_unexpected_warnings),
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
)
|
||||
Button(
|
||||
onClick = {
|
||||
UiUtils.launchUri(context, GoogleLoginFragment.URI_TESTED_WITH_GOOGLE)
|
||||
uriHandler.openUri(URI_TESTED_WITH_GOOGLE.toString())
|
||||
},
|
||||
colors = ButtonDefaults.outlinedButtonColors(),
|
||||
modifier = Modifier.wrapContentSize()
|
||||
|
@ -339,14 +348,21 @@ fun GoogleLogin(
|
|||
|
||||
Spacer(Modifier.padding(8.dp))
|
||||
|
||||
val privacyPolicyUrl = Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_PRIVACY)
|
||||
.withStatParams("GoogleLoginFragment")
|
||||
.build()
|
||||
val privacyPolicyNote = HtmlCompat.fromHtml(
|
||||
stringResource(R.string.login_google_client_privacy_policy, context.getString(R.string.app_name), App.homepageUrl(context, App.HOMEPAGE_PRIVACY)), 0).toAnnotatedString()
|
||||
stringResource(R.string.login_google_client_privacy_policy,
|
||||
context.getString(R.string.app_name),
|
||||
privacyPolicyUrl.toString()
|
||||
), 0).toAnnotatedString()
|
||||
ClickableText(
|
||||
privacyPolicyNote,
|
||||
style = MaterialTheme.typography.body2,
|
||||
onClick = { position ->
|
||||
privacyPolicyNote.getUrlAnnotations(position, position).firstOrNull()?.let {
|
||||
UiUtils.launchUri(context, it.item.url.toUri())
|
||||
uriHandler.openUri(it.item.url)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -359,7 +375,7 @@ fun GoogleLogin(
|
|||
modifier = Modifier.padding(top = 12.dp),
|
||||
onClick = { position ->
|
||||
limitedUseNote.getUrlAnnotations(position, position).firstOrNull()?.let {
|
||||
UiUtils.launchUri(context, it.item.url.toUri())
|
||||
uriHandler.openUri(it.item.url)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -11,7 +11,8 @@ import android.view.MenuItem
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.Constants.withStatParams
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.ui.UiUtils
|
||||
|
@ -61,7 +62,10 @@ class LoginActivity: AppCompatActivity() {
|
|||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
if (menuItem.itemId == R.id.help) {
|
||||
UiUtils.launchUri(this@LoginActivity,
|
||||
App.homepageUrl(this@LoginActivity).buildUpon().appendPath("tested-with").build())
|
||||
Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_TESTED_SERVICES)
|
||||
.withStatParams("LoginActivity")
|
||||
.build())
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ import at.bitfire.davdroid.R
|
|||
import at.bitfire.davdroid.db.Credentials
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.network.HttpClient
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import at.bitfire.davdroid.ui.UiUtils.haveCustomTabs
|
||||
import at.bitfire.vcard4android.GroupMethod
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
@ -124,7 +124,7 @@ class NextcloudLoginFlowFragment: Fragment() {
|
|||
|
||||
val view = ComposeView(requireActivity()).apply {
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
NextcloudLoginComposable(
|
||||
onStart = { url ->
|
||||
model.start(url)
|
||||
|
|
|
@ -34,6 +34,7 @@ import androidx.compose.material.Text
|
|||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.filled.Help
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
|
@ -51,17 +52,18 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import at.bitfire.dav4jvm.DavResource
|
||||
import at.bitfire.dav4jvm.UrlUtils
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.Constants.withStatParams
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
import at.bitfire.davdroid.db.Credentials
|
||||
import at.bitfire.davdroid.db.WebDavMount
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.network.HttpClient
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import at.bitfire.davdroid.ui.widget.PasswordTextField
|
||||
import at.bitfire.davdroid.webdav.CredentialsStore
|
||||
import at.bitfire.davdroid.webdav.DavDocumentsProvider
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -92,7 +94,7 @@ class AddWebdavMountActivity : AppCompatActivity() {
|
|||
val username by model.userName.observeAsState(initial = "")
|
||||
val password by model.password.observeAsState(initial = "")
|
||||
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
Layout(
|
||||
isLoading = isLoading,
|
||||
error = error,
|
||||
|
@ -146,16 +148,20 @@ class AddWebdavMountActivity : AppCompatActivity() {
|
|||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { onNavigateUp() }) {
|
||||
Icon(Icons.AutoMirrored.Default.ArrowBack, stringResource(R.string.navigate_up))
|
||||
}
|
||||
},
|
||||
title = { Text(stringResource(R.string.webdav_add_mount_title)) },
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = {
|
||||
uriHandler.openUri(
|
||||
App.homepageUrl(context)
|
||||
.buildUpon()
|
||||
.appendPath("tested-with")
|
||||
.build()
|
||||
.toString()
|
||||
Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_TESTED_SERVICES)
|
||||
.withStatParams("AddWebdavMountActivity")
|
||||
.build().toString()
|
||||
)
|
||||
}
|
||||
) {
|
||||
|
@ -299,7 +305,7 @@ class AddWebdavMountActivity : AppCompatActivity() {
|
|||
@Preview
|
||||
@Composable
|
||||
fun Layout_Preview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
Layout()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package at.bitfire.davdroid.ui.webdav
|
|||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.DocumentsContract
|
||||
|
@ -41,7 +42,6 @@ import androidx.compose.material.icons.automirrored.filled.Help
|
|||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -60,18 +60,17 @@ import androidx.core.text.HtmlCompat
|
|||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.Constants
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
import at.bitfire.davdroid.db.WebDavDocument
|
||||
import at.bitfire.davdroid.db.WebDavMount
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.ui.AppTheme
|
||||
import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
|
||||
import at.bitfire.davdroid.ui.widget.SafeAndroidUriHandler
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import at.bitfire.davdroid.webdav.CredentialsStore
|
||||
import at.bitfire.davdroid.webdav.DavDocumentsProvider
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -85,12 +84,9 @@ import javax.inject.Inject
|
|||
class WebdavMountsActivity: AppCompatActivity() {
|
||||
|
||||
companion object {
|
||||
|
||||
fun helpUrl(context: Context) =
|
||||
App.homepageUrl(context).buildUpon()
|
||||
.appendEncodedPath("manual/webdav_mounts.html")
|
||||
val helpUrl: Uri = Constants.MANUAL_URL.buildUpon()
|
||||
.appendPath(Constants.MANUAL_PATH_WEBDAV_MOUNTS)
|
||||
.build()
|
||||
|
||||
}
|
||||
|
||||
private val model by viewModels<Model>()
|
||||
|
@ -108,17 +104,12 @@ class WebdavMountsActivity: AppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
MdcTheme {
|
||||
CompositionLocalProvider(
|
||||
LocalUriHandler provides SafeAndroidUriHandler(this)
|
||||
) {
|
||||
AppTheme {
|
||||
val mountInfos by model.mountInfos.observeAsState(emptyList())
|
||||
|
||||
WebdavMountsContent(mountInfos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
|
@ -142,7 +133,9 @@ class WebdavMountsActivity: AppCompatActivity() {
|
|||
title = { Text(stringResource(R.string.webdav_mounts_title)) },
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = { uriHandler.openUri(helpUrl(context).toString()) }
|
||||
onClick = {
|
||||
uriHandler.openUri(helpUrl.toString())
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.Help,
|
||||
|
@ -209,7 +202,7 @@ class WebdavMountsActivity: AppCompatActivity() {
|
|||
val text = HtmlCompat.fromHtml(
|
||||
stringResource(
|
||||
R.string.webdav_add_mount_empty_more_info,
|
||||
helpUrl(context).toString()
|
||||
helpUrl.toString()
|
||||
),
|
||||
0
|
||||
).toAnnotatedString()
|
||||
|
@ -340,7 +333,7 @@ class WebdavMountsActivity: AppCompatActivity() {
|
|||
@Preview(showBackground = true, showSystemUi = true)
|
||||
@Composable
|
||||
fun WebdavMountsContent_Preview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
WebdavMountsContent(emptyList())
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +341,7 @@ class WebdavMountsActivity: AppCompatActivity() {
|
|||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun WebdavMountsItem_Preview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
WebdavMountsItem(
|
||||
info = MountInfo(
|
||||
mount = WebDavMount(
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
<!-- common strings -->
|
||||
<string name="app_name" translatable="false">DAVx⁵</string>
|
||||
<string name="homepage_url" translatable="false">https://www.davx5.com/</string>
|
||||
|
||||
<string name="account_invalid">Account does not exist (anymore)</string>
|
||||
<string name="account_type" translatable="false">bitfire.at.davdroid</string>
|
||||
|
|
Loading…
Reference in a new issue