change: Display "About" information in tabs (#420)
Previously, `AboutActivity` had buttons and links to show the privacy policy and licenses of dependencies. Change this to a selection of fragments in tabs, one tab each for: - General "About" information - Licenses - Privacy Policy The information shown hasn't changed, but this lays the groundwork for including additional tabs in the future for information like server rules, detected capabilities, or troubleshooting information.
This commit is contained in:
parent
7c5181d5c2
commit
41c702fc1b
|
@ -144,8 +144,6 @@
|
|||
android:resource="@xml/searchable" />
|
||||
</activity>
|
||||
<activity android:name=".ListsActivity" />
|
||||
<activity android:name=".feature.about.LicenseActivity" />
|
||||
<activity android:name=".feature.about.PrivacyPolicyActivity" />
|
||||
<activity android:name=".components.filters.FiltersActivity" />
|
||||
<activity android:name=".components.trending.TrendingActivity" />
|
||||
<activity android:name=".components.followedtags.FollowedTagsActivity" />
|
||||
|
|
|
@ -97,6 +97,7 @@ import app.pachli.core.navigation.TrendingActivityIntent
|
|||
import app.pachli.core.network.model.Account
|
||||
import app.pachli.core.network.model.Notification
|
||||
import app.pachli.core.preferences.PrefKeys
|
||||
import app.pachli.core.ui.reduceSwipeSensitivity
|
||||
import app.pachli.databinding.ActivityMainBinding
|
||||
import app.pachli.db.DraftsAlert
|
||||
import app.pachli.interfaces.ActionButtonActivity
|
||||
|
@ -110,7 +111,6 @@ import app.pachli.usecase.LogoutUsecase
|
|||
import app.pachli.util.await
|
||||
import app.pachli.util.deleteStaleCachedMedia
|
||||
import app.pachli.util.getDimension
|
||||
import app.pachli.util.reduceSwipeSensitivity
|
||||
import app.pachli.util.unsafeLazy
|
||||
import app.pachli.util.updateShortcut
|
||||
import at.connyduck.calladapter.networkresult.fold
|
||||
|
|
|
@ -77,6 +77,7 @@ import app.pachli.core.network.model.Relationship
|
|||
import app.pachli.core.network.parseAsMastodonHtml
|
||||
import app.pachli.core.preferences.AppTheme
|
||||
import app.pachli.core.preferences.PrefKeys
|
||||
import app.pachli.core.ui.reduceSwipeSensitivity
|
||||
import app.pachli.databinding.ActivityAccountBinding
|
||||
import app.pachli.db.DraftsAlert
|
||||
import app.pachli.interfaces.ActionButtonActivity
|
||||
|
@ -86,7 +87,6 @@ import app.pachli.util.Error
|
|||
import app.pachli.util.Loading
|
||||
import app.pachli.util.Success
|
||||
import app.pachli.util.getDomain
|
||||
import app.pachli.util.reduceSwipeSensitivity
|
||||
import app.pachli.util.setClickableText
|
||||
import app.pachli.view.showMuteAccountDialog
|
||||
import com.bumptech.glide.Glide
|
||||
|
|
|
@ -31,8 +31,8 @@ import app.pachli.components.search.adapter.SearchPagerAdapter
|
|||
import app.pachli.core.activity.BottomSheetActivity
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
import app.pachli.core.preferences.PrefKeys
|
||||
import app.pachli.core.ui.reduceSwipeSensitivity
|
||||
import app.pachli.databinding.ActivitySearchBinding
|
||||
import app.pachli.util.reduceSwipeSensitivity
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
|
|
|
@ -32,9 +32,9 @@ import app.pachli.components.timeline.TimelineFragment
|
|||
import app.pachli.core.activity.BottomSheetActivity
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
import app.pachli.core.network.model.TimelineKind
|
||||
import app.pachli.core.ui.reduceSwipeSensitivity
|
||||
import app.pachli.databinding.ActivityTrendingBinding
|
||||
import app.pachli.interfaces.AppBarLayoutHost
|
||||
import app.pachli.util.reduceSwipeSensitivity
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
|
@ -17,43 +17,6 @@
|
|||
package app.pachli.util
|
||||
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Reduce ViewPager2's sensitivity to horizontal swipes.
|
||||
*/
|
||||
fun ViewPager2.reduceSwipeSensitivity() {
|
||||
// ViewPager2 is very sensitive to horizontal motion when swiping vertically, and will
|
||||
// trigger a page transition if the user's swipe is only a few tens of degrees off from
|
||||
// vertical. This is a problem if the underlying content is a list that the user wants
|
||||
// to scroll vertically -- it's far too easy to trigger an accidental horizontal swipe.
|
||||
//
|
||||
// One way to stop this is to reach in to ViewPager2's RecyclerView and adjust the amount
|
||||
// of touch slop it has.
|
||||
//
|
||||
// See https://issuetracker.google.com/issues/139867645 and
|
||||
// https://bladecoder.medium.com/fixing-recyclerview-nested-scrolling-in-opposite-direction-f587be5c1a04
|
||||
// for more (the approach in that Medium article works, but is still quite sensitive to
|
||||
// horizontal movement while scrolling).
|
||||
try {
|
||||
val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
|
||||
recyclerViewField.isAccessible = true
|
||||
val recyclerView = recyclerViewField.get(this) as RecyclerView
|
||||
|
||||
val touchSlopField = RecyclerView::class.java.getDeclaredField("mTouchSlop")
|
||||
touchSlopField.isAccessible = true
|
||||
val touchSlop = touchSlopField.get(recyclerView) as Int
|
||||
// Experimentally, 2 seems to be a sweet-spot, requiring a downward swipe that's at least
|
||||
// 45 degrees off the vertical to trigger a change. This is consistent with maximum angle
|
||||
// supported to open the nav. drawer.
|
||||
val scaleFactor = 2
|
||||
touchSlopField.set(recyclerView, touchSlop * scaleFactor)
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("reduceSwipeSensitibity").w(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TextViews with an ancestor RecyclerView can forget that they are selectable. Toggling
|
||||
|
|
|
@ -549,12 +549,6 @@ class InstanceListActivityIntent(context: Context) : Intent() {
|
|||
}
|
||||
}
|
||||
|
||||
class LicenseActivityIntent(context: Context) : Intent() {
|
||||
init {
|
||||
setClassName(context, QuadrantConstants.LICENSE_ACTIVITY)
|
||||
}
|
||||
}
|
||||
|
||||
class ListActivityIntent(context: Context) : Intent() {
|
||||
init {
|
||||
setClassName(context, QuadrantConstants.LISTS_ACTIVITY)
|
||||
|
@ -567,12 +561,6 @@ class LoginWebViewActivityIntent(context: Context) : Intent() {
|
|||
}
|
||||
}
|
||||
|
||||
class PrivacyPolicyActivityIntent(context: Context) : Intent() {
|
||||
init {
|
||||
setClassName(context, QuadrantConstants.PRIVACY_POLICY_ACTIVITY)
|
||||
}
|
||||
}
|
||||
|
||||
class ScheduledStatusActivityIntent(context: Context) : Intent() {
|
||||
init {
|
||||
setClassName(context, QuadrantConstants.SCHEDULED_STATUS_ACTIVITY)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.core.ui
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Reduce ViewPager2's sensitivity to horizontal swipes.
|
||||
*/
|
||||
fun ViewPager2.reduceSwipeSensitivity() {
|
||||
// ViewPager2 is very sensitive to horizontal motion when swiping vertically, and will
|
||||
// trigger a page transition if the user's swipe is only a few tens of degrees off from
|
||||
// vertical. This is a problem if the underlying content is a list that the user wants
|
||||
// to scroll vertically -- it's far too easy to trigger an accidental horizontal swipe.
|
||||
//
|
||||
// One way to stop this is to reach in to ViewPager2's RecyclerView and adjust the amount
|
||||
// of touch slop it has.
|
||||
//
|
||||
// See https://issuetracker.google.com/issues/139867645 and
|
||||
// https://bladecoder.medium.com/fixing-recyclerview-nested-scrolling-in-opposite-direction-f587be5c1a04
|
||||
// for more (the approach in that Medium article works, but is still quite sensitive to
|
||||
// horizontal movement while scrolling).
|
||||
try {
|
||||
val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
|
||||
recyclerViewField.isAccessible = true
|
||||
val recyclerView = recyclerViewField.get(this) as RecyclerView
|
||||
|
||||
val touchSlopField = RecyclerView::class.java.getDeclaredField("mTouchSlop")
|
||||
touchSlopField.isAccessible = true
|
||||
val touchSlop = touchSlopField.get(recyclerView) as Int
|
||||
// Experimentally, 2 seems to be a sweet-spot, requiring a downward swipe that's at least
|
||||
// 45 degrees off the vertical to trigger a change. This is consistent with maximum angle
|
||||
// supported to open the nav. drawer.
|
||||
val scaleFactor = 2
|
||||
touchSlopField.set(recyclerView, touchSlop * scaleFactor)
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("reduceSwipeSensitibity").w(e)
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ dependencies {
|
|||
implementation(projects.core.activity)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.data)
|
||||
implementation(projects.core.designsystem)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.ui)
|
||||
|
||||
|
@ -57,4 +58,7 @@ dependencies {
|
|||
implementation(libs.bundles.androidx)
|
||||
|
||||
implementation(libs.bundles.aboutlibraries)
|
||||
|
||||
// For FixedSizeDrawable
|
||||
implementation(libs.glide.core)
|
||||
}
|
||||
|
|
|
@ -17,137 +17,83 @@
|
|||
|
||||
package app.pachli.feature.about
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.URLSpan
|
||||
import android.text.util.Linkify
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import app.pachli.core.activity.BottomSheetActivity
|
||||
import app.pachli.core.common.extensions.hide
|
||||
import app.pachli.core.common.extensions.show
|
||||
import app.pachli.core.common.util.versionName
|
||||
import app.pachli.core.data.repository.InstanceInfoRepository
|
||||
import app.pachli.core.navigation.LicenseActivityIntent
|
||||
import app.pachli.core.navigation.PrivacyPolicyActivityIntent
|
||||
import app.pachli.core.ui.NoUnderlineURLSpan
|
||||
import app.pachli.core.designsystem.R as DR
|
||||
import app.pachli.core.ui.reduceSwipeSensitivity
|
||||
import app.pachli.feature.about.databinding.ActivityAboutBinding
|
||||
import com.bumptech.glide.request.target.FixedSizeDrawable
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AboutActivity : BottomSheetActivity() {
|
||||
@Inject
|
||||
lateinit var instanceInfoRepository: InstanceInfoRepository
|
||||
|
||||
class AboutActivity : BottomSheetActivity(), MenuProvider {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val binding = ActivityAboutBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setSupportActionBar(binding.includedToolbar.toolbar)
|
||||
setSupportActionBar(binding.toolbar)
|
||||
binding.toolbar.run {
|
||||
val navIconSize = resources.getDimensionPixelSize(DR.dimen.avatar_toolbar_nav_icon_size)
|
||||
navigationIcon = FixedSizeDrawable(
|
||||
AppCompatResources.getDrawable(this@AboutActivity, DR.mipmap.ic_launcher),
|
||||
navIconSize,
|
||||
navIconSize,
|
||||
)
|
||||
}
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setTitle(R.string.app_name)
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
setTitle(R.string.about_title_activity)
|
||||
val adapter = AboutFragmentAdapter(this)
|
||||
binding.pager.adapter = adapter
|
||||
binding.pager.reduceSwipeSensitivity()
|
||||
|
||||
binding.versionTextView.text = getString(
|
||||
R.string.about_app_version,
|
||||
getString(
|
||||
R.string.app_name,
|
||||
),
|
||||
versionName(this),
|
||||
)
|
||||
TabLayoutMediator(binding.tabLayout, binding.pager) { tab, position ->
|
||||
tab.text = adapter.title(position)
|
||||
}.attach()
|
||||
|
||||
binding.deviceInfo.text = getString(
|
||||
R.string.about_device_info,
|
||||
Build.MANUFACTURER,
|
||||
Build.MODEL,
|
||||
Build.VERSION.RELEASE,
|
||||
Build.VERSION.SDK_INT,
|
||||
)
|
||||
|
||||
lifecycleScope.launch {
|
||||
accountManager.activeAccount?.let { account ->
|
||||
val instanceInfo = instanceInfoRepository.getInstanceInfo()
|
||||
binding.accountInfo.text = getString(
|
||||
R.string.about_account_info,
|
||||
account.username,
|
||||
account.domain,
|
||||
instanceInfo.version,
|
||||
)
|
||||
binding.accountInfoTitle.show()
|
||||
binding.accountInfo.show()
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.CUSTOM_INSTANCE.isBlank()) {
|
||||
binding.aboutPoweredBy.hide()
|
||||
}
|
||||
|
||||
binding.aboutLicenseInfoTextView.setClickableTextWithoutUnderlines(R.string.about_pachli_license)
|
||||
binding.aboutWebsiteInfoTextView.setClickableTextWithoutUnderlines(R.string.about_project_site)
|
||||
binding.aboutBugsFeaturesInfoTextView.setClickableTextWithoutUnderlines(R.string.about_bug_feature_request_site)
|
||||
|
||||
binding.aboutPrivacyPolicyTextView.setOnClickListener {
|
||||
startActivity(PrivacyPolicyActivityIntent(this))
|
||||
}
|
||||
|
||||
binding.appProfileButton.setOnClickListener {
|
||||
viewUrl(BuildConfig.SUPPORT_ACCOUNT_URL)
|
||||
}
|
||||
|
||||
binding.aboutLicensesButton.setOnClickListener {
|
||||
startActivityWithSlideInAnimation(LicenseActivityIntent(this))
|
||||
}
|
||||
|
||||
binding.copyDeviceInfo.setOnClickListener {
|
||||
val text = "${binding.versionTextView.text}\n\nDevice:\n\n${binding.deviceInfo.text}\n\nAccount:\n\n${binding.accountInfo.text}"
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Pachli version information", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
Toast.makeText(
|
||||
onBackPressedDispatcher.addCallback(
|
||||
this,
|
||||
getString(R.string.about_copied),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
object : OnBackPressedCallback(true) {
|
||||
@SuppressLint("SyntheticAccessor")
|
||||
override fun handleOnBackPressed() {
|
||||
if (binding.pager.currentItem != 0) binding.pager.currentItem = 0 else finish()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun TextView.setClickableTextWithoutUnderlines(@StringRes textId: Int) {
|
||||
val text = SpannableString(context.getText(textId))
|
||||
class AboutFragmentAdapter(val activity: FragmentActivity) : FragmentStateAdapter(activity) {
|
||||
override fun getItemCount() = 3
|
||||
|
||||
Linkify.addLinks(text, Linkify.WEB_URLS)
|
||||
|
||||
val builder = SpannableStringBuilder(text)
|
||||
val urlSpans = text.getSpans(0, text.length, URLSpan::class.java)
|
||||
for (span in urlSpans) {
|
||||
val start = builder.getSpanStart(span)
|
||||
val end = builder.getSpanEnd(span)
|
||||
val flags = builder.getSpanFlags(span)
|
||||
|
||||
val customSpan = NoUnderlineURLSpan(span.url)
|
||||
|
||||
builder.removeSpan(span)
|
||||
builder.setSpan(customSpan, start, end, flags)
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> AboutFragment.newInstance()
|
||||
1 -> LibsBuilder().supportFragment()
|
||||
2 -> PrivacyPolicyFragment.newInstance()
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
setText(builder)
|
||||
linksClickable = true
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
fun title(position: Int): CharSequence {
|
||||
return when (position) {
|
||||
0 -> "About"
|
||||
1 -> activity.getString(R.string.title_licenses)
|
||||
2 -> activity.getString(R.string.about_privacy_policy)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.feature.about
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.URLSpan
|
||||
import android.text.util.Linkify
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.pachli.core.activity.BottomSheetActivity
|
||||
import app.pachli.core.common.extensions.hide
|
||||
import app.pachli.core.common.extensions.show
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
import app.pachli.core.common.util.versionName
|
||||
import app.pachli.core.ui.NoUnderlineURLSpan
|
||||
import app.pachli.feature.about.databinding.FragmentAboutBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AboutFragment : Fragment(R.layout.fragment_about) {
|
||||
private val viewModel: AboutFragmentViewModel by viewModels()
|
||||
|
||||
private val binding by viewBinding(FragmentAboutBinding::bind)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val version = getString(
|
||||
R.string.about_app_version,
|
||||
getString(
|
||||
R.string.app_name,
|
||||
),
|
||||
versionName(requireContext()),
|
||||
)
|
||||
|
||||
binding.versionTextView.text = version
|
||||
|
||||
val deviceInfo = getString(
|
||||
R.string.about_device_info,
|
||||
Build.MANUFACTURER,
|
||||
Build.MODEL,
|
||||
Build.VERSION.RELEASE,
|
||||
Build.VERSION.SDK_INT,
|
||||
)
|
||||
binding.deviceInfo.text = deviceInfo
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.accountInfo.collect {
|
||||
binding.accountInfo.text = it
|
||||
binding.accountInfoTitle.show()
|
||||
binding.accountInfo.show()
|
||||
binding.copyDeviceInfo.show()
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.CUSTOM_INSTANCE.isBlank()) {
|
||||
binding.aboutPoweredBy.hide()
|
||||
}
|
||||
|
||||
binding.aboutLicenseInfoTextView.setClickableTextWithoutUnderlines(R.string.about_pachli_license)
|
||||
binding.aboutWebsiteInfoTextView.setClickableTextWithoutUnderlines(R.string.about_project_site)
|
||||
binding.aboutBugsFeaturesInfoTextView.setClickableTextWithoutUnderlines(R.string.about_bug_feature_request_site)
|
||||
|
||||
binding.appProfileButton.setOnClickListener {
|
||||
(activity as? BottomSheetActivity)?.viewUrl(BuildConfig.SUPPORT_ACCOUNT_URL)
|
||||
}
|
||||
|
||||
binding.copyDeviceInfo.setOnClickListener {
|
||||
val text = "$version\n\nDevice:\n\n$deviceInfo\n\nAccount:\n\n${binding.accountInfo.text}"
|
||||
val clipboard = getSystemService(requireContext(), ClipboardManager::class.java) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Pachli version information", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
getString(R.string.about_copied),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance() = AboutFragment()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun TextView.setClickableTextWithoutUnderlines(@StringRes textId: Int) {
|
||||
val text = SpannableString(context.getText(textId))
|
||||
|
||||
Linkify.addLinks(text, Linkify.WEB_URLS)
|
||||
|
||||
val builder = SpannableStringBuilder(text)
|
||||
val urlSpans = text.getSpans(0, text.length, URLSpan::class.java)
|
||||
for (span in urlSpans) {
|
||||
val start = builder.getSpanStart(span)
|
||||
val end = builder.getSpanEnd(span)
|
||||
val flags = builder.getSpanFlags(span)
|
||||
|
||||
val customSpan = NoUnderlineURLSpan(span.url)
|
||||
|
||||
builder.removeSpan(span)
|
||||
builder.setSpan(customSpan, start, end, flags)
|
||||
}
|
||||
|
||||
setText(builder)
|
||||
linksClickable = true
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.feature.about
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.pachli.core.accounts.AccountManager
|
||||
import app.pachli.core.data.repository.InstanceInfoRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@HiltViewModel
|
||||
class AboutFragmentViewModel @Inject constructor(
|
||||
private val application: Application,
|
||||
private val accountManager: AccountManager,
|
||||
private val instanceInfoRepository: InstanceInfoRepository,
|
||||
) : AndroidViewModel(application) {
|
||||
private val _accountInfo = MutableSharedFlow<String>()
|
||||
val accountInfo: Flow<String> = _accountInfo.asSharedFlow()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
accountManager.activeAccount?.let { account ->
|
||||
val instanceInfo = instanceInfoRepository.getInstanceInfo()
|
||||
_accountInfo.emit(
|
||||
application.getString(
|
||||
R.string.about_account_info,
|
||||
account.username,
|
||||
account.domain,
|
||||
instanceInfo.version,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.feature.about
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.commit
|
||||
import app.pachli.core.activity.BaseActivity
|
||||
import app.pachli.feature.about.databinding.ActivityLicenseBinding
|
||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LicenseActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val binding = ActivityLicenseBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setSupportActionBar(binding.includedToolbar.toolbar)
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
setTitle(R.string.title_licenses)
|
||||
|
||||
val fragment = LibsBuilder().supportFragment()
|
||||
if (savedInstanceState == null) {
|
||||
supportFragmentManager.commit {
|
||||
setReorderingAllowed(true)
|
||||
add(R.id.fragment_licenses, fragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,17 +19,23 @@ package app.pachli.feature.about
|
|||
|
||||
import android.os.Bundle
|
||||
import android.util.Base64
|
||||
import app.pachli.core.activity.BaseActivity
|
||||
import app.pachli.feature.about.databinding.ActivityPrivacyPolicyBinding
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
import app.pachli.feature.about.databinding.FragmentPrivacyPolicyBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PrivacyPolicyActivity : BaseActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val binding = ActivityPrivacyPolicyBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
class PrivacyPolicyFragment : Fragment(R.layout.fragment_privacy_policy) {
|
||||
private val binding by viewBinding(FragmentPrivacyPolicyBinding::bind)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val encoded = Base64.encodeToString(markdownR.html.PRIVACY_md.toByteArray(), Base64.NO_PADDING)
|
||||
binding.policy.loadData(encoded, "text/html", "base64")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance() = PrivacyPolicyFragment()
|
||||
}
|
||||
}
|
|
@ -1,4 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2024 Pachli Association
|
||||
~
|
||||
~ This file is a part of Pachli.
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
~ GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
~ License, or (at your option) any later version.
|
||||
~
|
||||
~ Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
~ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
~ Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
~ see <http://www.gnu.org/licenses>.
|
||||
-->
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
@ -6,215 +23,32 @@
|
|||
android:layout_height="match_parent"
|
||||
tools:context="app.pachli.feature.about.AboutActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/includedToolbar"
|
||||
layout="@layout/toolbar_basic" />
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/actionbar_elevation"
|
||||
app:elevationOverlayEnabled="false">
|
||||
|
||||
<FrameLayout
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_scrollFlags="scroll|enterAlways" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="fixed" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textDirection="anyRtl">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusableInTouchMode="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/versionTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
||||
android:textColor="?colorOnSurface"
|
||||
android:textIsSelectable="true"
|
||||
android:textStyle="normal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/logo"
|
||||
tools:text="Pachli Test" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceInfoTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginStart="@dimen/text_content_margin"
|
||||
android:layout_marginEnd="@dimen/text_content_margin"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:text="@string/about_device_info_title"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/versionTextView"
|
||||
tools:text="Your device" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceInfo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/deviceInfoTitle"
|
||||
app:layout_constraintStart_toStartOf="@+id/deviceInfoTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/deviceInfoTitle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accountInfoTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:text="@string/about_account_info_title"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toStartOf="@+id/copyDeviceInfo"
|
||||
app:layout_constraintStart_toStartOf="@+id/deviceInfo"
|
||||
app:layout_constraintTop_toBottomOf="@id/deviceInfo"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accountInfo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@+id/accountInfoTitle"
|
||||
app:layout_constraintStart_toStartOf="@+id/accountInfoTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/accountInfoTitle"
|
||||
tools:text="\@Pachli@mastodon.social\nVersion: xxx"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/copyDeviceInfo"
|
||||
style="@style/AppImageButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:contentDescription="@string/about_copy"
|
||||
android:layout_marginEnd="@dimen/text_content_margin"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/accountInfo"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:srcCompat="@drawable/ic_content_copy_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/about_powered_by"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/about_powered_by_pachli"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||
app:layout_constraintEnd_toEndOf="@+id/copyDeviceInfo"
|
||||
app:layout_constraintStart_toStartOf="@+id/deviceInfo"
|
||||
app:layout_constraintTop_toBottomOf="@+id/accountInfo" />
|
||||
|
||||
<app.pachli.core.ui.ClickableSpanTextView
|
||||
android:id="@+id/aboutLicenseInfoTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:hyphenationFrequency="full"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/copyDeviceInfo"
|
||||
app:layout_constraintStart_toStartOf="@+id/accountInfo"
|
||||
app:layout_constraintTop_toBottomOf="@id/about_powered_by"
|
||||
tools:text="@string/about_pachli_license" />
|
||||
|
||||
<app.pachli.core.ui.ClickableSpanTextView
|
||||
android:id="@+id/aboutWebsiteInfoTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/aboutLicenseInfoTextView"
|
||||
app:layout_constraintStart_toStartOf="@+id/aboutLicenseInfoTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/aboutLicenseInfoTextView"
|
||||
tools:text="@string/about_project_site" />
|
||||
|
||||
<app.pachli.core.ui.ClickableSpanTextView
|
||||
android:id="@+id/aboutBugsFeaturesInfoTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/about_bug_feature_request_site"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/aboutWebsiteInfoTextView"
|
||||
app:layout_constraintStart_toStartOf="@+id/aboutWebsiteInfoTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/aboutWebsiteInfoTextView" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/aboutPrivacyPolicyTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/about_privacy_policy"
|
||||
android:textColor="?android:attr/textColorLink"
|
||||
app:layout_constraintEnd_toEndOf="@+id/aboutWebsiteInfoTextView"
|
||||
app:layout_constraintStart_toStartOf="@+id/aboutWebsiteInfoTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/aboutBugsFeaturesInfoTextView" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/appProfileButton"
|
||||
style="@style/AppButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:maxWidth="320dp"
|
||||
android:text="@string/about_pachli_account"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginEnd="@dimen/text_content_margin"
|
||||
app:layout_constraintEnd_toStartOf="@+id/aboutLicensesButton"
|
||||
app:layout_constraintStart_toStartOf="@+id/aboutBugsFeaturesInfoTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/aboutPrivacyPolicyTextView" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/aboutLicensesButton"
|
||||
style="@style/AppButton.Outlined"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:maxWidth="320dp"
|
||||
android:text="@string/title_licenses"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginEnd="@dimen/text_content_margin"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/appProfileButton"
|
||||
app:layout_constraintTop_toTopOf="@+id/appProfileButton" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</FrameLayout>
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<include layout="@layout/item_status_bottom_sheet" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context="app.pachli.feature.about.LicenseActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/includedToolbar"
|
||||
layout="@layout/toolbar_basic" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:text="@string/license_description" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_licenses"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,160 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:textDirection="anyRtl"
|
||||
tools:context="app.pachli.feature.about.AboutActivity">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/versionTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textIsSelectable="true"
|
||||
android:textStyle="normal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Pachli Test" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceInfoTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="@dimen/text_content_margin"
|
||||
android:layout_marginEnd="@dimen/text_content_margin"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:text="@string/about_device_info_title"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/versionTextView"
|
||||
tools:text="Your device" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceInfo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/deviceInfoTitle"
|
||||
app:layout_constraintStart_toStartOf="@+id/deviceInfoTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/deviceInfoTitle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accountInfoTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:text="@string/about_account_info_title"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toStartOf="@+id/copyDeviceInfo"
|
||||
app:layout_constraintStart_toStartOf="@+id/deviceInfo"
|
||||
app:layout_constraintTop_toBottomOf="@id/deviceInfo"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accountInfo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@+id/accountInfoTitle"
|
||||
app:layout_constraintStart_toStartOf="@+id/accountInfoTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/accountInfoTitle"
|
||||
tools:text="\@Pachli@mastodon.social\nVersion: xxx"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/copyDeviceInfo"
|
||||
style="@style/AppImageButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:contentDescription="@string/about_copy"
|
||||
android:layout_marginEnd="@dimen/text_content_margin"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/accountInfo"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:srcCompat="@drawable/ic_content_copy_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/about_powered_by"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/about_powered_by_pachli"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||
app:layout_constraintEnd_toEndOf="@+id/copyDeviceInfo"
|
||||
app:layout_constraintStart_toStartOf="@+id/deviceInfo"
|
||||
app:layout_constraintTop_toBottomOf="@+id/accountInfo" />
|
||||
|
||||
<app.pachli.core.ui.ClickableSpanTextView
|
||||
android:id="@+id/aboutLicenseInfoTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:hyphenationFrequency="full"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/copyDeviceInfo"
|
||||
app:layout_constraintStart_toStartOf="@+id/accountInfo"
|
||||
app:layout_constraintTop_toBottomOf="@id/about_powered_by"
|
||||
tools:text="@string/about_pachli_license" />
|
||||
|
||||
<app.pachli.core.ui.ClickableSpanTextView
|
||||
android:id="@+id/aboutWebsiteInfoTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/aboutLicenseInfoTextView"
|
||||
app:layout_constraintStart_toStartOf="@+id/aboutLicenseInfoTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/aboutLicenseInfoTextView"
|
||||
tools:text="@string/about_project_site" />
|
||||
|
||||
<app.pachli.core.ui.ClickableSpanTextView
|
||||
android:id="@+id/aboutBugsFeaturesInfoTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/about_bug_feature_request_site"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="@+id/aboutWebsiteInfoTextView"
|
||||
app:layout_constraintStart_toStartOf="@+id/aboutWebsiteInfoTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/aboutWebsiteInfoTextView" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/appProfileButton"
|
||||
style="@style/AppButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:maxWidth="320dp"
|
||||
android:text="@string/about_pachli_account"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginEnd="@dimen/text_content_margin"
|
||||
app:layout_constraintStart_toStartOf="@+id/aboutBugsFeaturesInfoTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/aboutBugsFeaturesInfoTextView" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
|
@ -18,4 +18,6 @@
|
|||
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/policy"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/text_content_margin"
|
||||
android:layout_marginEnd="@dimen/text_content_margin" />
|
Loading…
Reference in New Issue