mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 18:53:32 +00:00
feat: Add list view toggle and separate applets settings category
- Add list/grid view toggle button to games fragment - Implement dual-view GameAdapter with separate ViewHolders for grid/list layouts - Create compact card_game_list.xml layout for list view - Add "Applets on Android" settings category to separate applet settings from Zep Zone - Add logging settings with log filter configuration - Add view toggle icons (ic_view_list, ic_view_grid) - Update strings.xml with new UI text and settings descriptions Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -23,6 +23,7 @@ import org.citron.citron_emu.HomeNavigationDirections
|
||||
import org.citron.citron_emu.R
|
||||
import org.citron.citron_emu.CitronApplication
|
||||
import org.citron.citron_emu.databinding.CardGameBinding
|
||||
import org.citron.citron_emu.databinding.CardGameListBinding
|
||||
import org.citron.citron_emu.model.Game
|
||||
import org.citron.citron_emu.model.GamesViewModel
|
||||
import org.citron.citron_emu.utils.GameIconUtils
|
||||
@@ -30,13 +31,41 @@ import org.citron.citron_emu.utils.ViewUtils.marquee
|
||||
import org.citron.citron_emu.viewholder.AbstractViewHolder
|
||||
|
||||
class GameAdapter(private val activity: AppCompatActivity) :
|
||||
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>(exact = false) {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
|
||||
CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
.also { return GameViewHolder(it) }
|
||||
AbstractDiffAdapter<Game, AbstractViewHolder<Game>>(exact = false) {
|
||||
|
||||
companion object {
|
||||
const val VIEW_TYPE_GRID = 0
|
||||
const val VIEW_TYPE_LIST = 1
|
||||
}
|
||||
|
||||
inner class GameViewHolder(val binding: CardGameBinding) :
|
||||
private var isListView = false
|
||||
|
||||
fun setListView(listView: Boolean) {
|
||||
if (isListView != listView) {
|
||||
isListView = listView
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (isListView) VIEW_TYPE_LIST else VIEW_TYPE_GRID
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder<Game> {
|
||||
return when (viewType) {
|
||||
VIEW_TYPE_GRID -> {
|
||||
val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
GameGridViewHolder(binding)
|
||||
}
|
||||
VIEW_TYPE_LIST -> {
|
||||
val binding = CardGameListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
GameListViewHolder(binding)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Invalid view type")
|
||||
}
|
||||
}
|
||||
|
||||
inner class GameGridViewHolder(val binding: CardGameBinding) :
|
||||
AbstractViewHolder<Game>(binding) {
|
||||
override fun bind(model: Game) {
|
||||
binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
@@ -50,50 +79,79 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||
}
|
||||
|
||||
fun onClick(game: Game) {
|
||||
val gameExists = DocumentFile.fromSingleUri(
|
||||
CitronApplication.appContext,
|
||||
Uri.parse(game.path)
|
||||
)?.exists() == true
|
||||
if (!gameExists) {
|
||||
Toast.makeText(
|
||||
CitronApplication.appContext,
|
||||
R.string.loader_error_file_not_found,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
|
||||
return
|
||||
}
|
||||
|
||||
val preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(CitronApplication.appContext)
|
||||
preferences.edit()
|
||||
.putLong(
|
||||
game.keyLastPlayedTime,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
.apply()
|
||||
|
||||
activity.lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val shortcut =
|
||||
ShortcutInfoCompat.Builder(CitronApplication.appContext, game.path)
|
||||
.setShortLabel(game.title)
|
||||
.setIcon(GameIconUtils.getShortcutIcon(activity, game))
|
||||
.setIntent(game.launchIntent)
|
||||
.build()
|
||||
ShortcutManagerCompat.pushDynamicShortcut(CitronApplication.appContext, shortcut)
|
||||
}
|
||||
}
|
||||
|
||||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true)
|
||||
binding.root.findNavController().navigate(action)
|
||||
handleGameClick(game)
|
||||
}
|
||||
|
||||
fun onLongClick(game: Game): Boolean {
|
||||
val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game)
|
||||
binding.root.findNavController().navigate(action)
|
||||
return true
|
||||
return handleGameLongClick(game)
|
||||
}
|
||||
}
|
||||
|
||||
inner class GameListViewHolder(val binding: CardGameListBinding) :
|
||||
AbstractViewHolder<Game>(binding) {
|
||||
override fun bind(model: Game) {
|
||||
binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
GameIconUtils.loadGameIcon(model, binding.imageGameScreen)
|
||||
|
||||
binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
|
||||
|
||||
binding.cardGame.setOnClickListener { onClick(model) }
|
||||
binding.cardGame.setOnLongClickListener { onLongClick(model) }
|
||||
}
|
||||
|
||||
fun onClick(game: Game) {
|
||||
handleGameClick(game)
|
||||
}
|
||||
|
||||
fun onLongClick(game: Game): Boolean {
|
||||
return handleGameLongClick(game)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleGameClick(game: Game) {
|
||||
val gameExists = DocumentFile.fromSingleUri(
|
||||
CitronApplication.appContext,
|
||||
Uri.parse(game.path)
|
||||
)?.exists() == true
|
||||
if (!gameExists) {
|
||||
Toast.makeText(
|
||||
CitronApplication.appContext,
|
||||
R.string.loader_error_file_not_found,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
|
||||
return
|
||||
}
|
||||
|
||||
val preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(CitronApplication.appContext)
|
||||
preferences.edit()
|
||||
.putLong(
|
||||
game.keyLastPlayedTime,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
.apply()
|
||||
|
||||
activity.lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val shortcut =
|
||||
ShortcutInfoCompat.Builder(CitronApplication.appContext, game.path)
|
||||
.setShortLabel(game.title)
|
||||
.setIcon(GameIconUtils.getShortcutIcon(activity, game))
|
||||
.setIntent(game.launchIntent)
|
||||
.build()
|
||||
ShortcutManagerCompat.pushDynamicShortcut(CitronApplication.appContext, shortcut)
|
||||
}
|
||||
}
|
||||
|
||||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true)
|
||||
activity.findNavController(R.id.fragment_container).navigate(action)
|
||||
}
|
||||
|
||||
private fun handleGameLongClick(game: Game): Boolean {
|
||||
val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game)
|
||||
activity.findNavController(R.id.fragment_container).navigate(action)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ object Settings {
|
||||
SECTION_INPUT_PLAYER_EIGHT,
|
||||
SECTION_THEME(R.string.preferences_theme),
|
||||
SECTION_DEBUG(R.string.preferences_debug),
|
||||
SECTION_ZEP_ZONE(R.string.preferences_zep_zone);
|
||||
SECTION_ZEP_ZONE(R.string.preferences_zep_zone),
|
||||
SECTION_APPLETS_ANDROID(R.string.preferences_applets_android);
|
||||
}
|
||||
|
||||
fun getPlayerString(player: Int): String =
|
||||
|
||||
@@ -7,7 +7,8 @@ import org.citron.citron_emu.utils.NativeConfig
|
||||
|
||||
enum class StringSetting(override val key: String) : AbstractStringSetting {
|
||||
DRIVER_PATH("driver_path"),
|
||||
DEVICE_NAME("device_name");
|
||||
DEVICE_NAME("device_name"),
|
||||
LOG_FILTER("log_filter");
|
||||
|
||||
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ class SettingsFragmentPresenter(
|
||||
MenuTag.SECTION_THEME -> addThemeSettings(sl)
|
||||
MenuTag.SECTION_DEBUG -> addDebugSettings(sl)
|
||||
MenuTag.SECTION_ZEP_ZONE -> addZepZoneSettings(sl)
|
||||
MenuTag.SECTION_APPLETS_ANDROID -> addAppletsAndroidSettings(sl)
|
||||
}
|
||||
settingsList = sl
|
||||
adapter.submitList(settingsList) {
|
||||
@@ -151,6 +152,14 @@ class SettingsFragmentPresenter(
|
||||
menuKey = MenuTag.SECTION_ZEP_ZONE
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
titleId = R.string.preferences_applets_android,
|
||||
descriptionId = R.string.preferences_applets_android_description,
|
||||
iconId = R.drawable.ic_applet,
|
||||
menuKey = MenuTag.SECTION_APPLETS_ANDROID
|
||||
)
|
||||
)
|
||||
add(
|
||||
RunnableSetting(
|
||||
titleId = R.string.reset_to_default,
|
||||
@@ -981,6 +990,15 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.CPU_ACCURACY.key)
|
||||
add(BooleanSetting.CPU_DEBUG_MODE.key)
|
||||
add(SettingsItem.FASTMEM_COMBINED)
|
||||
|
||||
add(HeaderSetting(R.string.logging))
|
||||
add(
|
||||
StringInputSetting(
|
||||
StringSetting.LOG_FILTER,
|
||||
titleId = R.string.log_filter,
|
||||
descriptionId = R.string.log_filter_description
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1000,7 +1018,11 @@ class SettingsFragmentPresenter(
|
||||
add(HeaderSetting(R.string.frame_skipping_header))
|
||||
add(IntSetting.FRAME_SKIPPING.key)
|
||||
add(IntSetting.FRAME_SKIPPING_MODE.key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addAppletsAndroidSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(HeaderSetting(R.string.applet_settings_header))
|
||||
add(IntSetting.CABINET_APPLET_MODE.key)
|
||||
add(IntSetting.CONTROLLER_APPLET_MODE.key)
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import org.citron.citron_emu.R
|
||||
import org.citron.citron_emu.adapters.GameAdapter
|
||||
@@ -31,6 +32,9 @@ class GamesFragment : Fragment() {
|
||||
private val gamesViewModel: GamesViewModel by activityViewModels()
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
|
||||
private lateinit var gameAdapter: GameAdapter
|
||||
private var isListView = false
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@@ -45,12 +49,19 @@ class GamesFragment : Fragment() {
|
||||
homeViewModel.setNavigationVisibility(visible = true, animated = true)
|
||||
homeViewModel.setStatusBarShadeVisibility(true)
|
||||
|
||||
gameAdapter = GameAdapter(requireActivity() as AppCompatActivity)
|
||||
|
||||
binding.gridGames.apply {
|
||||
layoutManager = AutofitGridLayoutManager(
|
||||
requireContext(),
|
||||
requireContext().resources.getDimensionPixelSize(R.dimen.card_width)
|
||||
)
|
||||
adapter = GameAdapter(requireActivity() as AppCompatActivity)
|
||||
adapter = gameAdapter
|
||||
}
|
||||
|
||||
// Set up button for view switching
|
||||
binding.btnViewToggle.setOnClickListener {
|
||||
toggleViewMode()
|
||||
}
|
||||
|
||||
binding.swipeRefresh.apply {
|
||||
@@ -90,14 +101,14 @@ class GamesFragment : Fragment() {
|
||||
)
|
||||
}
|
||||
gamesViewModel.games.collect(viewLifecycleOwner) {
|
||||
(binding.gridGames.adapter as GameAdapter).submitList(it)
|
||||
gameAdapter.submitList(it)
|
||||
}
|
||||
gamesViewModel.shouldSwapData.collect(
|
||||
viewLifecycleOwner,
|
||||
resetState = { gamesViewModel.setShouldSwapData(false) }
|
||||
) {
|
||||
if (it) {
|
||||
(binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value)
|
||||
gameAdapter.submitList(gamesViewModel.games.value)
|
||||
}
|
||||
}
|
||||
gamesViewModel.shouldScrollToTop.collect(
|
||||
@@ -108,6 +119,27 @@ class GamesFragment : Fragment() {
|
||||
setInsets()
|
||||
}
|
||||
|
||||
private fun toggleViewMode() {
|
||||
isListView = !isListView
|
||||
|
||||
if (isListView) {
|
||||
// Switch to list view
|
||||
binding.gridGames.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.btnViewToggle.setIconResource(R.drawable.ic_view_grid)
|
||||
binding.btnViewToggle.contentDescription = getString(R.string.switch_to_grid_view)
|
||||
} else {
|
||||
// Switch to grid view
|
||||
binding.gridGames.layoutManager = AutofitGridLayoutManager(
|
||||
requireContext(),
|
||||
requireContext().resources.getDimensionPixelSize(R.dimen.card_width)
|
||||
)
|
||||
binding.btnViewToggle.setIconResource(R.drawable.ic_view_list)
|
||||
binding.btnViewToggle.contentDescription = getString(R.string.switch_to_list_view)
|
||||
}
|
||||
|
||||
gameAdapter.setListView(isListView)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
@@ -155,6 +187,14 @@ class GamesFragment : Fragment() {
|
||||
|
||||
binding.noticeText.updatePadding(bottom = spacingNavigation)
|
||||
|
||||
// Update button margins
|
||||
val buttonSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab)
|
||||
binding.btnViewToggle.updateMargins(
|
||||
left = leftInsets + buttonSpacing,
|
||||
right = rightInsets + buttonSpacing,
|
||||
bottom = barInsets.bottom + spacingNavigation + buttonSpacing
|
||||
)
|
||||
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
|
||||
10
src/android/app/src/main/res/drawable/ic_view_grid.xml
Normal file
10
src/android/app/src/main/res/drawable/ic_view_grid.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorOnSurface">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,3v8h8L11,3L3,3zM9,9L5,9L5,5h4v4zM3,13v8h8v-8L3,13zM9,19L5,19v-4h4v4zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z"/>
|
||||
</vector>
|
||||
10
src/android/app/src/main/res/drawable/ic_view_list.xml
Normal file
10
src/android/app/src/main/res/drawable/ic_view_list.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorOnSurface">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,13h2v-2L3,11v2zM3,17h2v-2L3,15v2zM3,9h2L5,7L3,7v2zM7,13h14v-2L7,11v2zM7,17h14v-2L7,15v2zM7,7v2h14L21,7L7,7z"/>
|
||||
</vector>
|
||||
54
src/android/app/src/main/res/layout/card_game_list.xml
Normal file
54
src/android/app/src/main/res/layout/card_game_list.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_game"
|
||||
style="?attr/materialCardViewElevatedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:clipToPadding="false"
|
||||
android:focusable="true"
|
||||
android:transitionName="card_game"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="12dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/image_game_screen"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Small"
|
||||
tools:src="@drawable/default_icon" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_game_title"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="16sp"
|
||||
tools:text="The Legend of Zelda: Skyward Sword" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -2,6 +2,7 @@
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/swipe_refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -30,6 +31,18 @@
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
tools:listitem="@layout/card_game" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_view_toggle"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/switch_to_list_view"
|
||||
app:icon="@drawable/ic_view_list"
|
||||
app:iconSize="24dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
<string name="home_settings">Settings</string>
|
||||
<string name="empty_gamelist">No files were found or no game directory has been selected yet.</string>
|
||||
<string name="search_and_filter_games">Search and filter games</string>
|
||||
<string name="switch_to_list_view">Switch to list view</string>
|
||||
<string name="switch_to_grid_view">Switch to grid view</string>
|
||||
<string name="select_games_folder">Select games folder</string>
|
||||
<string name="manage_game_folders">Manage game folders</string>
|
||||
<string name="select_games_folder_description">Allows citron to populate the games list</string>
|
||||
@@ -256,6 +258,9 @@
|
||||
<string name="renderer_debug">Graphics debugging</string>
|
||||
<string name="renderer_debug_description">Sets the graphics API to a slow debugging mode.</string>
|
||||
<string name="fastmem">Fastmem</string>
|
||||
<string name="logging">Logging</string>
|
||||
<string name="log_filter">Log Filter</string>
|
||||
<string name="log_filter_description">Configure which log messages to display. Format: <class>:<level>. Example: *:Info Service:Debug</string>
|
||||
|
||||
<!-- Audio settings strings -->
|
||||
<string name="audio_output_engine">Output engine</string>
|
||||
@@ -418,6 +423,8 @@
|
||||
<string name="preferences_debug_description">CPU/GPU debugging, graphics API, fastmem</string>
|
||||
<string name="preferences_zep_zone">Zep Zone</string>
|
||||
<string name="preferences_zep_zone_description">Advanced emulation settings</string>
|
||||
<string name="preferences_applets_android">Applets on Android</string>
|
||||
<string name="preferences_applets_android_description">System applet configuration settings</string>
|
||||
|
||||
<!-- Zep Zone Headers -->
|
||||
<string name="memory_layout_header">Memory Layout</string>
|
||||
|
||||
@@ -634,7 +634,7 @@ struct Values {
|
||||
Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
|
||||
|
||||
// Miscellaneous
|
||||
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
|
||||
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Debugging};
|
||||
Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
|
||||
|
||||
// Network
|
||||
|
||||
Reference in New Issue
Block a user