Compare commits
10 Commits
0ca84a9502
...
71f1281e2b
Author | SHA1 | Date |
---|---|---|
Fred | 71f1281e2b | |
Matthieu | 04324577ea | |
Matthieu | 73f08e5a5f | |
Matthieu | a7feab380b | |
Matthieu | 018f893388 | |
Fred | bbcaa46b36 | |
Fred | b4330d7ac3 | |
Fred | 073a6a4489 | |
Fred | 1cfb9aecb3 | |
Fred | a46c37766f |
|
@ -223,21 +223,21 @@ dependencies {
|
|||
implementation 'com.google.android.material:material:1.11.0'
|
||||
|
||||
//Dagger (dependency injection)
|
||||
implementation 'com.google.dagger:dagger:2.50'
|
||||
ksp 'com.google.dagger:dagger-compiler:2.50'
|
||||
implementation 'com.google.dagger:dagger:2.51'
|
||||
ksp 'com.google.dagger:dagger-compiler:2.51'
|
||||
|
||||
implementation("com.google.dagger:hilt-android:2.50")
|
||||
ksp "com.google.dagger:hilt-compiler:2.50"
|
||||
implementation('com.google.dagger:hilt-android:2.51')
|
||||
ksp 'com.google.dagger:hilt-compiler:2.51'
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.10.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.10.0'
|
||||
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.10.0'
|
||||
implementation 'io.reactivex.rxjava3:rxjava:3.1.8'
|
||||
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
|
||||
implementation 'com.github.connyduck:sparkbutton:4.1.0'
|
||||
|
||||
implementation 'org.pixeldroid.pixeldroid:android-media-editor:1.7'
|
||||
implementation 'org.pixeldroid.pixeldroid:android-media-editor:2.0'
|
||||
implementation project(path: ':scrambler')
|
||||
implementation project(path: ':pixel_common')
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
|
@ -16,6 +17,8 @@ import androidx.activity.addCallback
|
|||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
|
@ -25,6 +28,7 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
|
@ -48,6 +52,8 @@ import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
|
|||
import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
||||
import com.mikepenz.materialdrawer.widget.AccountHeaderView
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.ligi.tracedroid.sending.sendTraceDroidStackTracesIfExist
|
||||
import org.pixeldroid.app.databinding.ActivityMainBinding
|
||||
import org.pixeldroid.app.postCreation.camera.CameraFragment
|
||||
|
@ -65,11 +71,14 @@ import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity
|
|||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.updateUserInfoDb
|
||||
import org.pixeldroid.app.utils.hasInternet
|
||||
import org.pixeldroid.app.utils.loadDefaultMenuTabs
|
||||
import org.pixeldroid.app.utils.loadJsonMenuTabs
|
||||
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.INSTANCE_NOTIFICATION_TAG
|
||||
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.SHOW_NOTIFICATION_TAG
|
||||
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.USER_NOTIFICATION_TAG
|
||||
import org.pixeldroid.app.utils.notificationsWorker.enablePullNotifications
|
||||
import org.pixeldroid.app.utils.notificationsWorker.removeNotificationChannelsFromAccount
|
||||
import org.pixeldroid.app.utils.toList
|
||||
import java.time.Instant
|
||||
|
||||
|
||||
|
@ -86,7 +95,6 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen().setOnExitAnimationListener {
|
||||
it.remove()
|
||||
|
@ -112,24 +120,8 @@ class MainActivity : BaseActivity() {
|
|||
sendTraceDroidStackTracesIfExist("contact@pixeldroid.org", this)
|
||||
|
||||
setupDrawer()
|
||||
val tabs: List<() -> Fragment> = listOf(
|
||||
{
|
||||
PostFeedFragment<HomeStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", true) }
|
||||
}
|
||||
},
|
||||
{ SearchDiscoverFragment() },
|
||||
{ CameraFragment() },
|
||||
{ NotificationsFragment() },
|
||||
{
|
||||
PostFeedFragment<PublicFeedStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", false) }
|
||||
}
|
||||
}
|
||||
)
|
||||
setupTabs(tabs)
|
||||
|
||||
setupTabs()
|
||||
|
||||
val showNotification: Boolean = intent.getBooleanExtra(SHOW_NOTIFICATION_TAG, false)
|
||||
|
||||
|
@ -396,29 +388,103 @@ class MainActivity : BaseActivity() {
|
|||
touchSlopField.set(recyclerView, touchSlop*NestedScrollableHost.touchSlopModifier)
|
||||
}
|
||||
|
||||
private fun setupTabs(tab_array: List<() -> Fragment>){
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
private fun setupTabs() {
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
val tabsCheckedString = sharedPreferences.getString("tabsChecked", null)
|
||||
val pageIds = listOf(R.id.page_1, R.id.page_2, R.id.page_3, R.id.page_4, R.id.page_5)
|
||||
|
||||
fun getDrawable(title: String): Drawable? {
|
||||
val resId = when (title) {
|
||||
getString(R.string.home_feed) -> R.drawable.selector_home_feed
|
||||
getString(R.string.search_discover_feed) -> R.drawable.ic_search_white_24dp
|
||||
getString(R.string.create_feed) -> R.drawable.selector_camera
|
||||
getString(R.string.notifications_feed) -> R.drawable.selector_notifications
|
||||
getString(R.string.public_feed) -> R.drawable.ic_filter_black_24dp
|
||||
else -> 0
|
||||
}
|
||||
if (resId == 0) {
|
||||
return null
|
||||
} else {
|
||||
return AppCompatResources.getDrawable(applicationContext, resId)
|
||||
}
|
||||
}
|
||||
|
||||
fun getFragment(title: String): (() -> Fragment)? {
|
||||
return when (title) {
|
||||
getString(R.string.home_feed) -> { {
|
||||
PostFeedFragment<HomeStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", true) }
|
||||
}
|
||||
} }
|
||||
getString(R.string.search_discover_feed) -> { { SearchDiscoverFragment() } }
|
||||
getString(R.string.create_feed) -> { { CameraFragment() } }
|
||||
getString(R.string.notifications_feed) -> { { NotificationsFragment() } }
|
||||
getString(R.string.public_feed) -> { {
|
||||
PostFeedFragment<PublicFeedStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", false) }
|
||||
}
|
||||
} }
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
val tabs = if (tabsCheckedString == null) {
|
||||
// Load default menu
|
||||
loadDefaultMenuTabs(applicationContext, binding.root)
|
||||
} else {
|
||||
// Get current menu visibility and order from settings
|
||||
val tabsChecked = loadJsonMenuTabs(tabsCheckedString).filter { it.second }.map { it.first }
|
||||
|
||||
val bottomNavigationMenu: Menu = binding.tabs.menu
|
||||
bottomNavigationMenu.clear()
|
||||
|
||||
tabsChecked.zip(pageIds).forEach { (tabTitle, pageId) ->
|
||||
with(bottomNavigationMenu.add(0, pageId, Menu.NONE, tabTitle)) {
|
||||
val tabIcon = getDrawable(tabTitle)
|
||||
if (tabIcon != null) {
|
||||
icon = tabIcon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tabsChecked
|
||||
}
|
||||
|
||||
val tabArray: List<() -> Fragment> = tabs.map { getFragment(it)!! }
|
||||
|
||||
binding.viewPager.reduceDragSensitivity()
|
||||
binding.viewPager.adapter = object : FragmentStateAdapter(this) {
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return tab_array[position]()
|
||||
return tabArray[position]()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return tab_array.size
|
||||
return tabArray.size
|
||||
}
|
||||
}
|
||||
|
||||
val notificationId = tabs.zip(pageIds).find {
|
||||
it.first == getString(R.string.notifications_feed)
|
||||
}?.second
|
||||
|
||||
fun doAtPageId(pageId: Int): Int {
|
||||
if (notificationId != null && pageId == notificationId) {
|
||||
setNotificationBadge(false)
|
||||
}
|
||||
return pageId
|
||||
}
|
||||
|
||||
binding.viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
val selected = when(position){
|
||||
0 -> R.id.page_1
|
||||
1 -> R.id.page_2
|
||||
2 -> R.id.page_3
|
||||
3 -> {
|
||||
setNotificationBadge(false)
|
||||
R.id.page_4
|
||||
}
|
||||
4 -> R.id.page_5
|
||||
0 -> doAtPageId(R.id.page_1)
|
||||
1 -> doAtPageId(R.id.page_2)
|
||||
2 -> doAtPageId(R.id.page_3)
|
||||
3 -> doAtPageId(R.id.page_4)
|
||||
4 -> doAtPageId(R.id.page_5)
|
||||
else -> null
|
||||
}
|
||||
if (selected != null) {
|
||||
|
|
|
@ -39,6 +39,8 @@ import org.pixeldroid.app.utils.bindingLifecycleAware
|
|||
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
||||
import org.pixeldroid.app.utils.fileExtension
|
||||
import org.pixeldroid.app.utils.getMimeType
|
||||
import org.pixeldroid.media_editor.common.PICTURE_POSITION
|
||||
import org.pixeldroid.media_editor.common.PICTURE_URI
|
||||
import org.pixeldroid.media_editor.photoEdit.PhotoEditActivity
|
||||
import org.pixeldroid.media_editor.videoEdit.VideoEditActivity
|
||||
import java.io.File
|
||||
|
@ -47,7 +49,6 @@ import java.text.SimpleDateFormat
|
|||
import java.util.Locale
|
||||
|
||||
class PostCreationFragment : BaseFragment() {
|
||||
|
||||
private var binding: FragmentPostCreationBinding by bindingLifecycleAware()
|
||||
private val model: PostCreationViewModel by activityViewModels()
|
||||
|
||||
|
@ -307,7 +308,7 @@ class PostCreationFragment : BaseFragment() {
|
|||
ActivityResultContracts.StartActivityForResult()){
|
||||
result: ActivityResult? ->
|
||||
if (result?.resultCode == Activity.RESULT_OK && result.data != null) {
|
||||
val position: Int = result.data!!.getIntExtra(PhotoEditActivity.PICTURE_POSITION, 0)
|
||||
val position: Int = result.data!!.getIntExtra(PICTURE_POSITION, 0)
|
||||
model.modifyAt(position, result.data!!)
|
||||
?: Toast.makeText(requireActivity(), R.string.error_editing, Toast.LENGTH_SHORT).show()
|
||||
} else if(result?.resultCode != Activity.RESULT_CANCELED){
|
||||
|
@ -320,8 +321,8 @@ class PostCreationFragment : BaseFragment() {
|
|||
requireActivity(),
|
||||
if (model.getPhotoData().value!![position].video) VideoEditActivity::class.java else PhotoEditActivity::class.java
|
||||
)
|
||||
.putExtra(PhotoEditActivity.PICTURE_URI, model.getPhotoData().value!![position].imageUri)
|
||||
.putExtra(PhotoEditActivity.PICTURE_POSITION, position)
|
||||
.putExtra(PICTURE_URI, model.getPhotoData().value!![position].imageUri)
|
||||
.putExtra(PICTURE_POSITION, position)
|
||||
|
||||
editResultContract.launch(intent)
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
|||
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
||||
import org.pixeldroid.app.utils.fileExtension
|
||||
import org.pixeldroid.app.utils.getMimeType
|
||||
import org.pixeldroid.media_editor.common.PICTURE_URI
|
||||
import org.pixeldroid.media_editor.videoEdit.VideoEditActivity
|
||||
import retrofit2.HttpException
|
||||
import java.io.File
|
||||
|
@ -299,7 +300,7 @@ class PostCreationViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
imageUri = data.getStringExtra(org.pixeldroid.media_editor.photoEdit.PhotoEditActivity.PICTURE_URI)!!.toUri()
|
||||
imageUri = data.getStringExtra(PICTURE_URI)!!.toUri()
|
||||
val (imageSize, imageVideo) = getSizeAndVideoValidate(imageUri, position)
|
||||
size = imageSize
|
||||
video = imageVideo
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
package org.pixeldroid.app.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import androidx.activity.addCallback
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.os.LocaleListCompat
|
||||
|
@ -14,12 +21,22 @@ import androidx.preference.ListPreference
|
|||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.checkbox.MaterialCheckBox
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.pixeldroid.app.MainActivity
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.databinding.SettingsBinding
|
||||
import org.pixeldroid.common.ThemedActivity
|
||||
import org.pixeldroid.app.utils.loadDefaultMenuTabs
|
||||
import org.pixeldroid.app.utils.loadJsonMenuTabs
|
||||
import org.pixeldroid.app.utils.setThemeFromPreferences
|
||||
import org.pixeldroid.common.ThemedActivity
|
||||
|
||||
|
||||
class SettingsActivity : ThemedActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
@ -103,6 +120,8 @@ class SettingsActivity : ThemedActivity(), SharedPreferences.OnSharedPreferenceC
|
|||
dialogFragment = ColorPreferenceDialog((preference as ColorPreference?)!!)
|
||||
} else if(preference.key == "language"){
|
||||
dialogFragment = LanguageSettingFragment()
|
||||
} else if (preference.key == "arrange_tabs") {
|
||||
dialogFragment = ArrangeTabsFragment()
|
||||
}
|
||||
if (dialogFragment != null) {
|
||||
dialogFragment.setTargetFragment(this, 0)
|
||||
|
@ -132,6 +151,7 @@ class SettingsActivity : ThemedActivity(), SharedPreferences.OnSharedPreferenceC
|
|||
|
||||
}
|
||||
class LanguageSettingFragment : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val list: MutableList<String> = mutableListOf()
|
||||
// IDE doesn't find it, but compiling works apparently?
|
||||
|
@ -175,3 +195,131 @@ class LanguageSettingFragment : DialogFragment() {
|
|||
}.create()
|
||||
}
|
||||
}
|
||||
|
||||
class ArrangeTabsFragment: DialogFragment() {
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
||||
val inflater: LayoutInflater = requireActivity().layoutInflater
|
||||
val dialogView: View = inflater.inflate(R.layout.layout_tabs_arrange, null)
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
||||
val tabsCheckedString = sharedPreferences.getString("tabsChecked", null)
|
||||
|
||||
val map = if (tabsCheckedString == null) {
|
||||
// Load default menu
|
||||
val list = loadDefaultMenuTabs(requireContext(), dialogView)
|
||||
list.zip(List(list.size){true}.toTypedArray()).toMutableList()
|
||||
} else {
|
||||
// Get current menu visibility and order from settings
|
||||
loadJsonMenuTabs(tabsCheckedString).toMutableList()
|
||||
}
|
||||
|
||||
val listFeed: RecyclerView = dialogView.findViewById(R.id.tabs)
|
||||
val listAdapter = ListViewAdapter(map)
|
||||
listFeed.adapter = listAdapter
|
||||
listFeed.layoutManager = LinearLayoutManager(requireActivity())
|
||||
val callback = object: ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) {
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
source: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
listAdapter.onItemMove(source.bindingAdapterPosition, target.bindingAdapterPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
// Do nothing, all items should remain in the list
|
||||
}
|
||||
}
|
||||
val itemTouchHelper = ItemTouchHelper(callback)
|
||||
itemTouchHelper.attachToRecyclerView(listFeed)
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setIcon(R.drawable.outline_bottom_navigation)
|
||||
setTitle(R.string.arrange_tabs_summary)
|
||||
setView(dialogView)
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
// Save values into preferences
|
||||
val tabsChecked = listAdapter.tabsChecked.toList()
|
||||
val tabsJson = JSONArray()
|
||||
val checkedJson = JSONArray()
|
||||
|
||||
tabsChecked.forEach { (k, v) ->
|
||||
tabsJson.put(k)
|
||||
checkedJson.put(v.toString())
|
||||
}
|
||||
|
||||
val tabsCheckedJson = JSONObject().apply {
|
||||
put("tabs", tabsJson)
|
||||
put("checked", checkedJson)
|
||||
}.toString()
|
||||
|
||||
sharedPreferences.edit().putString("tabsChecked", tabsCheckedJson).apply()
|
||||
}
|
||||
}.create()
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
inner class ListViewAdapter(val tabsChecked: MutableList<Pair<String, Boolean>>):
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = FrameLayout.inflate(context, R.layout.layout_tab, null)
|
||||
|
||||
// Make sure the layout occupies full width
|
||||
view.layoutParams = FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
|
||||
return object: RecyclerView.ViewHolder(view) {}
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val textView: MaterialButton = holder.itemView.findViewById(R.id.textView)
|
||||
val checkBox: MaterialCheckBox = holder.itemView.findViewById(R.id.checkBox)
|
||||
val dragHandle: ImageView = holder.itemView.findViewById(R.id.dragHandle)
|
||||
|
||||
// Set content of each entry
|
||||
textView.text = tabsChecked[position].first
|
||||
checkBox.isChecked = tabsChecked[position].second
|
||||
|
||||
// Also interact with checkbox when button is clicked
|
||||
textView.setOnClickListener {
|
||||
val isCheckedNew = !tabsChecked[position].second
|
||||
tabsChecked[position] = Pair(tabsChecked[position].first, isCheckedNew)
|
||||
checkBox.isChecked = isCheckedNew
|
||||
|
||||
// Disable OK button when no tab is selected or when strictly more than 5 tabs are selected
|
||||
val maxItemCount = BottomNavigationView(requireContext()).maxItemCount // = 5
|
||||
(requireDialog() as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled =
|
||||
with (tabsChecked.count { (_, v) -> v }) { this in 1..maxItemCount}
|
||||
}
|
||||
|
||||
// Also highlight button when checkbox is clicked
|
||||
checkBox.setOnTouchListener { _, motionEvent ->
|
||||
textView.dispatchTouchEvent(motionEvent)
|
||||
}
|
||||
|
||||
// Do not highlight the button when the drag handle is touched
|
||||
dragHandle.setOnTouchListener { _, _ -> true }
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return tabsChecked.size
|
||||
}
|
||||
|
||||
fun onItemMove(from: Int, to: Int) {
|
||||
val previous = tabsChecked.removeAt(from)
|
||||
tabsChecked.add(to, previous)
|
||||
notifyItemMoved(from, to)
|
||||
notifyItemChanged(to) // necessary to avoid checkBox issues
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,11 +11,13 @@ import android.net.ConnectivityManager
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
|
@ -28,6 +30,8 @@ import com.google.gson.JsonElement
|
|||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializer
|
||||
import okhttp3.HttpUrl
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.pixeldroid.app.R
|
||||
import java.time.Instant
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
@ -193,3 +197,23 @@ fun <T> Fragment.bindingLifecycleAware(): ReadWriteProperty<Fragment, T> =
|
|||
this@bindingLifecycleAware.viewLifecycleOwner.lifecycle.addObserver(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun JSONArray.toList(): List<String> {
|
||||
return (0 until this.length()).map { this.get(it).toString() }
|
||||
}
|
||||
|
||||
fun loadDefaultMenuTabs(context: Context, anchor: View): List<String> {
|
||||
return with(PopupMenu(context, anchor)) {
|
||||
val menu = this.menu
|
||||
menuInflater.inflate(R.menu.bottom_navigation_main, menu)
|
||||
(0 until menu.size()).map { menu.getItem(it).title.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
fun loadJsonMenuTabs(jsonString: String): List<Pair<String, Boolean>> {
|
||||
val tabsCheckedJson = JSONObject(jsonString)
|
||||
val tabs = tabsCheckedJson.getJSONArray("tabs").toList()
|
||||
val checked = tabsCheckedJson.getJSONArray("checked").toList().map { v -> v.toBoolean() }
|
||||
return tabs.zip(checked)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="960" android:viewportWidth="960"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnBackground" android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,600L760,600L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,600ZM200,680L200,760Q200,760 200,760Q200,760 200,760L760,760Q760,760 760,760Q760,760 760,760L760,680L200,680ZM200,680L200,680L200,760Q200,760 200,760Q200,760 200,760L200,760Q200,760 200,760Q200,760 200,760L200,680Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="960" android:viewportWidth="960"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnBackground" android:pathData="M346,820L100,574Q90,564 85,552Q80,540 80,527Q80,514 85,502Q90,490 100,480L330,251L255,176Q242,163 241.5,145Q241,127 254,113Q267,99 286,99Q305,99 319,113L686,480Q696,490 700.5,502Q705,514 705,527Q705,540 700.5,552Q696,564 686,574L440,820Q430,830 418,835Q406,840 393,840Q380,840 368,835Q356,830 346,820ZM393,314L179,528Q179,528 179,528Q179,528 179,528L607,528Q607,528 607,528Q607,528 607,528L393,314ZM792,840Q756,840 731,814.5Q706,789 706,752Q706,725 719.5,701Q733,677 750,654L769,630Q778,619 792.5,618.5Q807,618 816,629L836,654Q852,677 866,701Q880,725 880,752Q880,789 854,814.5Q828,840 792,840Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="960" android:viewportWidth="960"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnBackground" android:pathData="M200,600Q183,600 171.5,588.5Q160,577 160,560Q160,543 171.5,531.5Q183,520 200,520L760,520Q777,520 788.5,531.5Q800,543 800,560Q800,577 788.5,588.5Q777,600 760,600L200,600ZM200,440Q183,440 171.5,428.5Q160,417 160,400Q160,383 171.5,371.5Q183,360 200,360L760,360Q777,360 788.5,371.5Q800,383 800,400Q800,417 788.5,428.5Q777,440 760,440L200,440Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout 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="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cornerRadius="0dp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="?attr/textAppearanceBody1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingStart="75dp"
|
||||
android:paddingEnd="75dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5" />
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/checkBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="40dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/textView"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/textView"
|
||||
app:layout_constraintVertical_bias="0.5"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dragHandle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:src="@drawable/rounded_drag_handle"
|
||||
android:paddingEnd="15dp"
|
||||
android:paddingStart="15dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/textView"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/textView"
|
||||
app:layout_constraintVertical_bias="0.5"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.widget.Space
|
||||
android:id="@+id/titleDividerNoCustom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/m3_alert_dialog_title_bottom_margin"
|
||||
/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
|
@ -348,4 +348,7 @@ For more info about Pixelfed, you can check here: https://pixelfed.org"</string>
|
|||
<string name="continue_post_creation">Continue</string>
|
||||
<string name="extraneous_pictures_stories">Pictures after the first were removed but can be restored by switching back to creating a Post</string>
|
||||
<string name="story_duration">Story Duration</string>
|
||||
<string name="arrange_tabs_summary">Arrange tabs</string>
|
||||
<string name="arrange_tabs_description">Change visibility and order of tabs</string>
|
||||
<string name="content_header">Content</string>
|
||||
</resources>
|
||||
|
|
|
@ -17,54 +17,64 @@
|
|||
android:title="@string/accentColorTitle"
|
||||
android:key="themeColor"
|
||||
android:defaultValue="0"
|
||||
android:summary="@string/accentColorSummary" />
|
||||
android:summary="@string/accentColorSummary"
|
||||
app:icon="@drawable/rounded_colors"/>
|
||||
|
||||
<ListPreference
|
||||
app:key="language"
|
||||
app:title="@string/language"
|
||||
app:icon="@drawable/translate_black_24dp" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<ListPreference
|
||||
app:key="language"
|
||||
app:title="@string/language"
|
||||
app:icon="@drawable/translate_black_24dp" />
|
||||
<PreferenceCategory app:title="@string/content_header">
|
||||
<ListPreference
|
||||
android:key="arrange_tabs"
|
||||
android:title="@string/arrange_tabs_summary"
|
||||
android:summary="@string/arrange_tabs_description"
|
||||
android:icon="@drawable/outline_bottom_navigation" />
|
||||
|
||||
<CheckBoxPreference app:key="always_show_nsfw" app:title="@string/always_show_nsfw"
|
||||
app:icon="@drawable/eye_black_24dp" android:defaultValue="false"
|
||||
android:summary="@string/summary_always_show_nsfw"/>
|
||||
<CheckBoxPreference app:key="always_show_nsfw" app:title="@string/always_show_nsfw"
|
||||
app:icon="@drawable/eye_black_24dp" android:defaultValue="false"
|
||||
android:summary="@string/summary_always_show_nsfw"/>
|
||||
|
||||
<Preference android:title="@string/notifications_settings"
|
||||
android:key="notification"
|
||||
android:summary="@string/notifications_settings_summary"
|
||||
app:icon="@drawable/ic_baseline_notifications_active_24">
|
||||
<intent android:action="android.settings.APP_NOTIFICATION_SETTINGS">
|
||||
<extra android:name="android.provider.extra.APP_PACKAGE"
|
||||
android:value="@string/application_id" />
|
||||
</intent>
|
||||
</Preference>
|
||||
<EditTextPreference android:title="@string/description_template"
|
||||
android:key="prefill_description"
|
||||
android:summary="@string/description_template_summary"
|
||||
app:icon="@drawable/note" />
|
||||
|
||||
<EditTextPreference android:title="@string/description_template"
|
||||
android:key="prefill_description"
|
||||
android:summary="@string/description_template_summary"
|
||||
app:icon="@drawable/note" />
|
||||
<Preference android:title="@string/notifications_settings"
|
||||
android:key="notification"
|
||||
android:summary="@string/notifications_settings_summary"
|
||||
app:icon="@drawable/ic_baseline_notifications_active_24">
|
||||
<intent android:action="android.settings.APP_NOTIFICATION_SETTINGS">
|
||||
<extra android:name="android.provider.extra.APP_PACKAGE"
|
||||
android:value="@string/application_id" />
|
||||
</intent>
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
|
||||
<Preference android:title="@string/about"
|
||||
android:key="about"
|
||||
android:summary="@string/about_pixeldroid"
|
||||
app:icon="@drawable/info_black_24dp">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetPackage="@string/application_id"
|
||||
android:targetClass="org.pixeldroid.common.AboutActivity">
|
||||
<extra android:name="buildVersion" android:value="@string/versionName" />
|
||||
<extra android:name="appImage" android:value="mascot" />
|
||||
<extra android:name="appImageWidth" android:value="508" />
|
||||
<extra android:name="appImageTopMargin" android:value="-130" />
|
||||
<extra android:name="appImageBottomMargin" android:value="-130" />
|
||||
<extra android:name="appImageLeftMargin" android:value="0" />
|
||||
<extra android:name="appImageRightMargin" android:value="0" />
|
||||
<extra android:name="appName" android:value="@string/app_name" />
|
||||
<extra android:name="aboutAppDescription" android:value="@string/license_info" />
|
||||
<extra android:name="website" android:value="@string/project_website" />
|
||||
<extra android:name="translatePlatformUrl" android:value="https://weblate.pixeldroid.org" />
|
||||
<extra android:name="contributeForgeUrl" android:value="https://gitlab.shinice.net/pixeldroid/PixelDroid" />
|
||||
</intent>
|
||||
|
||||
</Preference>
|
||||
<PreferenceCategory app:title="@string/about">
|
||||
<Preference android:title="@string/about"
|
||||
android:key="about"
|
||||
android:summary="@string/about_pixeldroid"
|
||||
app:icon="@drawable/info_black_24dp">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetPackage="@string/application_id"
|
||||
android:targetClass="org.pixeldroid.common.AboutActivity">
|
||||
<extra android:name="buildVersion" android:value="@string/versionName" />
|
||||
<extra android:name="appImage" android:value="mascot" />
|
||||
<extra android:name="appImageWidth" android:value="508" />
|
||||
<extra android:name="appImageTopMargin" android:value="-130" />
|
||||
<extra android:name="appImageBottomMargin" android:value="-130" />
|
||||
<extra android:name="appImageLeftMargin" android:value="0" />
|
||||
<extra android:name="appImageRightMargin" android:value="0" />
|
||||
<extra android:name="appName" android:value="@string/app_name" />
|
||||
<extra android:name="aboutAppDescription" android:value="@string/license_info" />
|
||||
<extra android:name="website" android:value="@string/project_website" />
|
||||
<extra android:name="translatePlatformUrl" android:value="https://weblate.pixeldroid.org" />
|
||||
<extra android:name="contributeForgeUrl" android:value="https://gitlab.shinice.net/pixeldroid/PixelDroid" />
|
||||
</intent>
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.2.2'
|
||||
classpath 'com.android.tools.build:gradle:8.3.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 956bd5f88d6189009f2ba0a8cb2860a1bfee0ee6
|
||||
Subproject commit 702d14fe701343958337efa1b4eb31f0250849f6
|
|
@ -1 +1 @@
|
|||
Subproject commit 7c67b911930b4344a2917f2944493e08fdd04b57
|
||||
Subproject commit 23d4d94b45a848f0c64a042985eb03d0acc2f18b
|
Loading…
Reference in New Issue