mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 23:40:33 +05:30
move the base views to the UI package
This commit is contained in:
parent
6813772d2f
commit
5b4102ec57
@ -16,8 +16,8 @@ import com.github.libretube.constants.PIPED_GITHUB_URL
|
||||
import com.github.libretube.constants.WEBLATE_URL
|
||||
import com.github.libretube.constants.WEBSITE_URL
|
||||
import com.github.libretube.databinding.ActivityAboutBinding
|
||||
import com.github.libretube.extensions.BaseActivity
|
||||
import com.github.libretube.extensions.getStyledSnackBar
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
|
@ -9,7 +9,7 @@ import com.github.libretube.constants.REDDIT_URL
|
||||
import com.github.libretube.constants.TELEGRAM_URL
|
||||
import com.github.libretube.constants.TWITTER_URL
|
||||
import com.github.libretube.databinding.ActivityCommunityBinding
|
||||
import com.github.libretube.extensions.BaseActivity
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
|
||||
class CommunityActivity : BaseActivity() {
|
||||
private lateinit var binding: ActivityCommunityBinding
|
||||
|
@ -25,12 +25,12 @@ import com.github.libretube.R
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.ActivityMainBinding
|
||||
import com.github.libretube.extensions.BaseActivity
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.models.PlayerViewModel
|
||||
import com.github.libretube.models.SearchViewModel
|
||||
import com.github.libretube.models.SubscriptionsViewModel
|
||||
import com.github.libretube.services.ClosingService
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.dialogs.ErrorDialog
|
||||
import com.github.libretube.ui.fragments.PlayerFragment
|
||||
import com.github.libretube.util.NavBarHelper
|
||||
|
@ -5,8 +5,8 @@ import android.os.Bundle
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.ActivityNointernetBinding
|
||||
import com.github.libretube.extensions.BaseActivity
|
||||
import com.github.libretube.extensions.getStyledSnackBar
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.fragments.DownloadsFragment
|
||||
import com.github.libretube.util.NetworkHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
|
@ -12,7 +12,7 @@ import androidx.core.view.WindowInsetsControllerCompat
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.databinding.ActivityOfflinePlayerBinding
|
||||
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
||||
import com.github.libretube.extensions.BaseActivity
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.util.DownloadHelper
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
|
@ -7,8 +7,8 @@ import android.os.Bundle
|
||||
import android.util.Log
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.extensions.BaseActivity
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
|
||||
class RouterActivity : BaseActivity() {
|
||||
|
@ -4,7 +4,7 @@ import android.os.Bundle
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.ActivitySettingsBinding
|
||||
import com.github.libretube.extensions.BaseActivity
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.preferences.MainSettings
|
||||
|
||||
class SettingsActivity : BaseActivity() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.extensions
|
||||
package com.github.libretube.ui.base
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.extensions
|
||||
package com.github.libretube.ui.base
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.ui.views
|
||||
package com.github.libretube.ui.base
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.EditTextPreference
|
||||
@ -13,7 +13,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
/**
|
||||
* PreferenceFragmentCompat using the [MaterialAlertDialogBuilder] instead of the old dialog builder
|
||||
*/
|
||||
open class MaterialPreferenceFragment : PreferenceFragmentCompat() {
|
||||
open class BasePreferenceFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {}
|
||||
|
||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
@ -12,11 +12,11 @@ import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.SubscriptionHelper
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.databinding.FragmentChannelBinding
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.ui.adapters.ChannelAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
@ -8,8 +8,8 @@ import androidx.core.view.size
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.FragmentDownloadsBinding
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.ui.adapters.DownloadsAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.DownloadHelper
|
||||
|
||||
class DownloadsFragment : BaseFragment() {
|
||||
|
@ -13,10 +13,10 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.FragmentHomeBinding
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.ui.adapters.ChannelAdapter
|
||||
import com.github.libretube.ui.adapters.TrendingAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import retrofit2.HttpException
|
||||
|
@ -15,10 +15,10 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.FragmentLibraryBinding
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.models.PlayerViewModel
|
||||
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.dialogs.CreatePlaylistDialog
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import retrofit2.HttpException
|
||||
|
@ -45,7 +45,6 @@ import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
||||
import com.github.libretube.databinding.FragmentPlayerBinding
|
||||
import com.github.libretube.db.DatabaseHelper
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.formatShort
|
||||
@ -60,6 +59,7 @@ import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.adapters.ChaptersAdapter
|
||||
import com.github.libretube.ui.adapters.CommentsAdapter
|
||||
import com.github.libretube.ui.adapters.TrendingAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.dialogs.AddToPlaylistDialog
|
||||
import com.github.libretube.ui.dialogs.DownloadDialog
|
||||
import com.github.libretube.ui.dialogs.ShareDialog
|
||||
|
@ -13,11 +13,11 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.databinding.FragmentPlaylistBinding
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.ui.adapters.PlaylistAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
|
@ -13,13 +13,13 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.databinding.FragmentSearchBinding
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.models.SearchViewModel
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.adapters.SearchHistoryAdapter
|
||||
import com.github.libretube.ui.adapters.SearchSuggestionsAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
|
@ -14,11 +14,11 @@ import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.FragmentSearchResultBinding
|
||||
import com.github.libretube.db.DatabaseHelper
|
||||
import com.github.libretube.db.obj.SearchHistoryItem
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.hideKeyboard
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.adapters.SearchAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
@ -12,11 +12,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.models.SubscriptionsViewModel
|
||||
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
||||
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
|
||||
import com.github.libretube.ui.adapters.TrendingAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.views.BottomSheet
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
|
@ -9,9 +9,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.FragmentWatchHistoryBinding
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.BaseFragment
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.ui.adapters.WatchHistoryAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
|
||||
class WatchHistoryFragment : BaseFragment() {
|
||||
private lateinit var binding: FragmentWatchHistoryBinding
|
||||
|
@ -11,14 +11,14 @@ import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.obj.BackupFile
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.BackupDialog
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.util.BackupHelper
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class AdvancedSettings : MaterialPreferenceFragment() {
|
||||
class AdvancedSettings : BasePreferenceFragment() {
|
||||
|
||||
// backup and restore database
|
||||
private lateinit var getBackupFile: ActivityResultLauncher<String>
|
||||
|
@ -11,13 +11,13 @@ import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.RequireRestartDialog
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.material.color.DynamicColors
|
||||
|
||||
class AppearanceSettings : MaterialPreferenceFragment() {
|
||||
class AppearanceSettings : BasePreferenceFragment() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.appearance_settings, rootKey)
|
||||
|
||||
|
@ -3,9 +3,9 @@ package com.github.libretube.ui.preferences
|
||||
import android.os.Bundle
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
|
||||
class AudioVideoSettings : MaterialPreferenceFragment() {
|
||||
class AudioVideoSettings : BasePreferenceFragment() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.audio_video_settings, rootKey)
|
||||
|
@ -8,12 +8,12 @@ import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.NavBarOptionsDialog
|
||||
import com.github.libretube.ui.dialogs.RequireRestartDialog
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class GeneralSettings : MaterialPreferenceFragment() {
|
||||
class GeneralSettings : BasePreferenceFragment() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.general_settings, rootKey)
|
||||
|
@ -7,10 +7,10 @@ import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class HistorySettings : MaterialPreferenceFragment() {
|
||||
class HistorySettings : BasePreferenceFragment() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.history_settings, rootKey)
|
||||
|
@ -17,15 +17,15 @@ import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.CustomInstanceDialog
|
||||
import com.github.libretube.ui.dialogs.DeleteAccountDialog
|
||||
import com.github.libretube.ui.dialogs.LoginDialog
|
||||
import com.github.libretube.ui.dialogs.LogoutDialog
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.util.ImportHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class InstanceSettings : MaterialPreferenceFragment() {
|
||||
class InstanceSettings : BasePreferenceFragment() {
|
||||
|
||||
/**
|
||||
* result listeners for importing and exporting subscriptions
|
||||
|
@ -8,14 +8,14 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.extensions.getStyledSnackBar
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.UpdateDialog
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.util.NetworkHelper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainSettings : MaterialPreferenceFragment() {
|
||||
class MainSettings : BasePreferenceFragment() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.settings, rootKey)
|
||||
|
@ -7,10 +7,10 @@ import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.util.NotificationHelper
|
||||
|
||||
class NotificationSettings : MaterialPreferenceFragment() {
|
||||
class NotificationSettings : BasePreferenceFragment() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.notification_settings, rootKey)
|
||||
|
@ -7,11 +7,11 @@ import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import java.util.*
|
||||
|
||||
class PlayerSettings : MaterialPreferenceFragment() {
|
||||
class PlayerSettings : BasePreferenceFragment() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.player_settings, rootKey)
|
||||
|
@ -3,9 +3,9 @@ package com.github.libretube.ui.preferences
|
||||
import android.os.Bundle
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.views.MaterialPreferenceFragment
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
|
||||
class SponsorBlockSettings : MaterialPreferenceFragment() {
|
||||
class SponsorBlockSettings : BasePreferenceFragment() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.sponsorblock_settings, rootKey)
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.extensions
|
||||
package com.github.libretube.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@ -8,6 +8,7 @@ import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.constants.PreferenceRanges
|
||||
import com.github.libretube.databinding.DialogSliderBinding
|
||||
import com.github.libretube.extensions.setSliderRangeAndValue
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
@ -70,7 +70,7 @@
|
||||
|
||||
<PreferenceCategory app:title="@string/background_mode">
|
||||
|
||||
<com.github.libretube.extensions.SliderPreference
|
||||
<com.github.libretube.ui.views.SliderPreference
|
||||
android:icon="@drawable/ic_speed"
|
||||
app:defaultValue="1.0"
|
||||
app:key="background_playback_speed"
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<PreferenceCategory app:title="@string/player">
|
||||
|
||||
<com.github.libretube.extensions.SliderPreference
|
||||
<com.github.libretube.ui.views.SliderPreference
|
||||
android:icon="@drawable/ic_speed"
|
||||
app:defaultValue="1.0"
|
||||
app:key="playback_speed"
|
||||
|
Loading…
x
Reference in New Issue
Block a user