Code Cleanup
This commit is contained in:
parent
fcdf9ad590
commit
cda7af4420
14 changed files with 33 additions and 37 deletions
|
@ -15,7 +15,6 @@
|
||||||
package code.name.monkey.retromusic.activities
|
package code.name.monkey.retromusic.activities
|
||||||
|
|
||||||
import android.app.KeyguardManager
|
import android.app.KeyguardManager
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
@ -84,7 +83,7 @@ class LockScreenActivity : AbsMusicServiceActivity() {
|
||||||
|
|
||||||
@Suppress("Deprecation")
|
@Suppress("Deprecation")
|
||||||
private fun lockScreenInit() {
|
private fun lockScreenInit() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
if (VersionUtils.hasOreoMR1()) {
|
||||||
setShowWhenLocked(true)
|
setShowWhenLocked(true)
|
||||||
val keyguardManager = getSystemService<KeyguardManager>()
|
val keyguardManager = getSystemService<KeyguardManager>()
|
||||||
keyguardManager?.requestDismissKeyguard(this, null)
|
keyguardManager?.requestDismissKeyguard(this, null)
|
||||||
|
|
|
@ -49,14 +49,17 @@ class PermissionActivity : AbsMusicServiceActivity() {
|
||||||
binding.storagePermission.setButtonClick {
|
binding.storagePermission.setButtonClick {
|
||||||
requestPermissions()
|
requestPermissions()
|
||||||
}
|
}
|
||||||
if (VersionUtils.hasMarshmallow()) binding.audioPermission.show()
|
if (VersionUtils.hasMarshmallow()) {
|
||||||
binding.audioPermission.setButtonClick {
|
binding.audioPermission.show()
|
||||||
if (RingtoneManager.requiresDialog(this@PermissionActivity)) {
|
binding.audioPermission.setButtonClick {
|
||||||
val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
|
if (RingtoneManager.requiresDialog(this@PermissionActivity)) {
|
||||||
intent.data = Uri.parse("package:" + applicationContext.packageName)
|
val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
|
||||||
startActivity(intent)
|
intent.data = Uri.parse("package:" + applicationContext.packageName)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.finish.accentBackgroundColor()
|
binding.finish.accentBackgroundColor()
|
||||||
binding.finish.setOnClickListener {
|
binding.finish.setOnClickListener {
|
||||||
if (hasPermissions()) {
|
if (hasPermissions()) {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import android.content.pm.PackageManager
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
@ -31,6 +30,7 @@ import android.widget.EditText
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
|
||||||
|
@ -62,19 +62,12 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
|
||||||
permissionDeniedMessage = null
|
permissionDeniedMessage = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPostCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onPostCreate(savedInstanceState)
|
|
||||||
if (!hasPermissions()) {
|
|
||||||
// requestPermissions()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
val hasPermissions = hasPermissions()
|
val hasPermissions = hasPermissions()
|
||||||
if (hasPermissions != hadPermissions) {
|
if (hasPermissions != hadPermissions) {
|
||||||
hadPermissions = hasPermissions
|
hadPermissions = hasPermissions
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (VersionUtils.hasMarshmallow()) {
|
||||||
onHasPermissionsChanged(hasPermissions)
|
onHasPermissionsChanged(hasPermissions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,13 +90,13 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun requestPermissions() {
|
protected open fun requestPermissions() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (VersionUtils.hasMarshmallow()) {
|
||||||
requestPermissions(permissions, PERMISSION_REQUEST)
|
requestPermissions(permissions, PERMISSION_REQUEST)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun hasPermissions(): Boolean {
|
protected fun hasPermissions(): Boolean {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (VersionUtils.hasMarshmallow()) {
|
||||||
for (permission in permissions) {
|
for (permission in permissions) {
|
||||||
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
|
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -24,7 +24,6 @@ import android.content.res.Resources
|
||||||
import android.graphics.*
|
import android.graphics.*
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
@ -101,7 +100,7 @@ abstract class BaseAppWidget : AppWidgetProvider() {
|
||||||
): PendingIntent {
|
): PendingIntent {
|
||||||
val intent = Intent(action)
|
val intent = Intent(action)
|
||||||
intent.component = serviceName
|
intent.component = serviceName
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
return if (VersionUtils.hasOreo()) {
|
||||||
PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.getService(
|
PendingIntent.getService(
|
||||||
|
|
|
@ -3,11 +3,11 @@ package code.name.monkey.retromusic.dialogs
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
@ -49,7 +49,7 @@ class BlacklistFolderChooserDialog : DialogFragment() {
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
var mSavedInstanceState = savedInstanceState
|
var mSavedInstanceState = savedInstanceState
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
if (VersionUtils.hasMarshmallow()
|
||||||
&& ActivityCompat.checkSelfPermission(
|
&& ActivityCompat.checkSelfPermission(
|
||||||
requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE
|
requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
)
|
)
|
||||||
|
|
|
@ -45,7 +45,7 @@ fun AppCompatActivity.setImmersiveFullscreen() {
|
||||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
hide(WindowInsetsCompat.Type.systemBars())
|
hide(WindowInsetsCompat.Type.systemBars())
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (VersionUtils.hasP()) {
|
||||||
window.attributes.layoutInDisplayCutoutMode =
|
window.attributes.layoutInDisplayCutoutMode =
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ fun FragmentActivity.setTaskDescriptionColor(color: Int) {
|
||||||
// Task description requires fully opaque color
|
// Task description requires fully opaque color
|
||||||
colorFinal = ColorUtil.stripAlpha(colorFinal)
|
colorFinal = ColorUtil.stripAlpha(colorFinal)
|
||||||
// Sets color of entry in the system recents page
|
// Sets color of entry in the system recents page
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (VersionUtils.hasP()) {
|
||||||
setTaskDescription(
|
setTaskDescription(
|
||||||
ActivityManager.TaskDescription(
|
ActivityManager.TaskDescription(
|
||||||
title as String?,
|
title as String?,
|
||||||
|
@ -196,7 +196,7 @@ fun AppCompatActivity.setStatusBarColorAuto() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AppCompatActivity.setNavigationBarColor(color: Int) {
|
fun AppCompatActivity.setNavigationBarColor(color: Int) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (VersionUtils.hasOreo()) {
|
||||||
window.navigationBarColor = color
|
window.navigationBarColor = color
|
||||||
} else {
|
} else {
|
||||||
window.navigationBarColor = ColorUtil.darkenColor(color)
|
window.navigationBarColor = ColorUtil.darkenColor(color)
|
||||||
|
|
|
@ -22,7 +22,6 @@ import android.content.Intent
|
||||||
import android.graphics.drawable.AnimatedVectorDrawable
|
import android.graphics.drawable.AnimatedVectorDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.view.GestureDetector
|
import android.view.GestureDetector
|
||||||
|
@ -297,7 +296,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
||||||
playerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
|
playerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
|
||||||
playerAlbumCoverFragment?.setCallbacks(this)
|
playerAlbumCoverFragment?.setCallbacks(this)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
if (VersionUtils.hasMarshmallow())
|
||||||
view.findViewById<RelativeLayout>(R.id.statusBarShadow)?.hide()
|
view.findViewById<RelativeLayout>(R.id.statusBarShadow)?.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import android.view.animation.LinearInterpolator
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.databinding.FragmentTinyPlayerBinding
|
import code.name.monkey.retromusic.databinding.FragmentTinyPlayerBinding
|
||||||
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||||
|
@ -283,7 +284,7 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player),
|
||||||
@Suppress("Deprecation")
|
@Suppress("Deprecation")
|
||||||
private fun vibrate() {
|
private fun vibrate() {
|
||||||
val v = requireContext().getSystemService<Vibrator>()
|
val v = requireContext().getSystemService<Vibrator>()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (VersionUtils.hasOreo()) {
|
||||||
v?.vibrate(VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE))
|
v?.vibrate(VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||||
} else {
|
} else {
|
||||||
v?.vibrate(10)
|
v?.vibrate(10)
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
package code.name.monkey.retromusic.fragments.settings
|
package code.name.monkey.retromusic.fragments.settings
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.TwoStatePreference
|
import androidx.preference.TwoStatePreference
|
||||||
|
@ -48,7 +47,7 @@ class ThemeSettingsFragment : AbsSettingsFragment() {
|
||||||
setSummary(it, newValue)
|
setSummary(it, newValue)
|
||||||
ThemeStore.markChanged(requireContext())
|
ThemeStore.markChanged(requireContext())
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
if (VersionUtils.hasNougatMR()) {
|
||||||
requireActivity().setTheme(PreferenceUtil.themeResFromPrefValue(theme))
|
requireActivity().setTheme(PreferenceUtil.themeResFromPrefValue(theme))
|
||||||
DynamicShortcutManager(requireContext()).updateDynamicShortcuts()
|
DynamicShortcutManager(requireContext()).updateDynamicShortcuts()
|
||||||
}
|
}
|
||||||
|
@ -83,7 +82,7 @@ class ThemeSettingsFragment : AbsSettingsFragment() {
|
||||||
return@setOnPreferenceChangeListener false
|
return@setOnPreferenceChangeListener false
|
||||||
}
|
}
|
||||||
ThemeStore.markChanged(requireContext())
|
ThemeStore.markChanged(requireContext())
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
if (VersionUtils.hasNougatMR()) {
|
||||||
requireActivity().setTheme(PreferenceUtil.themeResFromPrefValue("black"))
|
requireActivity().setTheme(PreferenceUtil.themeResFromPrefValue("black"))
|
||||||
DynamicShortcutManager(requireContext()).updateDynamicShortcuts()
|
DynamicShortcutManager(requireContext()).updateDynamicShortcuts()
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.os.Environment
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
import android.provider.MediaStore.Audio.Media
|
import android.provider.MediaStore.Audio.Media
|
||||||
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
||||||
import code.name.monkey.retromusic.Constants.baseProjection
|
import code.name.monkey.retromusic.Constants.baseProjection
|
||||||
import code.name.monkey.retromusic.extensions.getInt
|
import code.name.monkey.retromusic.extensions.getInt
|
||||||
|
@ -188,7 +189,7 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
||||||
selectionFinal =
|
selectionFinal =
|
||||||
selectionFinal + " AND " + Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
|
selectionFinal + " AND " + Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
|
||||||
}
|
}
|
||||||
val uri = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
|
val uri = if (VersionUtils.hasQ()) {
|
||||||
Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
|
Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
|
||||||
} else {
|
} else {
|
||||||
Media.EXTERNAL_CONTENT_URI
|
Media.EXTERNAL_CONTENT_URI
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
|
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
|
||||||
|
@ -324,7 +323,7 @@ class PlayingNotificationClassic(
|
||||||
context: Context,
|
context: Context,
|
||||||
notificationManager: NotificationManager
|
notificationManager: NotificationManager
|
||||||
): PlayingNotification {
|
): PlayingNotification {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (VersionUtils.hasOreo()) {
|
||||||
createNotificationChannel(context, notificationManager)
|
createNotificationChannel(context, notificationManager)
|
||||||
}
|
}
|
||||||
return PlayingNotificationClassic(context)
|
return PlayingNotificationClassic(context)
|
||||||
|
|
|
@ -232,7 +232,7 @@ class PlayingNotificationImpl24(
|
||||||
notificationManager: NotificationManager,
|
notificationManager: NotificationManager,
|
||||||
mediaSession: MediaSessionCompat
|
mediaSession: MediaSessionCompat
|
||||||
): PlayingNotification {
|
): PlayingNotification {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (VersionUtils.hasOreo()) {
|
||||||
createNotificationChannel(context, notificationManager)
|
createNotificationChannel(context, notificationManager)
|
||||||
}
|
}
|
||||||
return PlayingNotificationImpl24(context, mediaSession.sessionToken)
|
return PlayingNotificationImpl24(context, mediaSession.sessionToken)
|
||||||
|
|
|
@ -49,6 +49,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper;
|
import code.name.monkey.appthemehelper.util.TintHelper;
|
||||||
|
import code.name.monkey.appthemehelper.util.VersionUtils;
|
||||||
import code.name.monkey.retromusic.App;
|
import code.name.monkey.retromusic.App;
|
||||||
|
|
||||||
public class RetroUtil {
|
public class RetroUtil {
|
||||||
|
|
|
@ -22,6 +22,8 @@ import android.provider.BaseColumns
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.MusicUtil.getSongFileUri
|
import code.name.monkey.retromusic.util.MusicUtil.getSongFileUri
|
||||||
|
@ -55,7 +57,7 @@ class RingtoneManager(val context: Context) {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun requiresDialog(context: Context): Boolean {
|
fun requiresDialog(context: Context): Boolean {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (VersionUtils.hasMarshmallow()) {
|
||||||
if (!Settings.System.canWrite(context)) {
|
if (!Settings.System.canWrite(context)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue