From 80dac7d9e9944d65bf3e4f25ce2c6c516f4426eb Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Sat, 20 Jul 2024 13:48:58 -0600 Subject: [PATCH] detail: eliminate dead code --- .../auxio/detail/AlbumDetailFragment.kt | 22 +- .../auxio/detail/ArtistDetailFragment.kt | 33 +-- .../oxycblt/auxio/detail/DetailFragment.kt | 16 +- .../auxio/detail/GenreDetailFragment.kt | 24 +-- .../auxio/detail/PlaylistDetailFragment.kt | 34 +-- .../fragment_detail.xml} | 0 .../res/layout-h600dp/item_detail_header.xml | 88 -------- .../fragment_detail.xml} | 0 .../res/layout-land/item_detail_header.xml | 103 --------- .../res/layout-sw600dp/fragment_detail.xml | 203 ++++++++++++++++++ .../res/layout-sw600dp/item_detail_header.xml | 105 --------- .../res/layout-sw840dp/item_detail_header.xml | 100 --------- app/src/main/res/layout/fragment_detail.xml | 181 +++++++++++++--- .../main/res/layout/item_detail_header.xml | 90 -------- 14 files changed, 380 insertions(+), 619 deletions(-) rename app/src/main/res/{layout/fragment_detail2.xml => layout-h480dp/fragment_detail.xml} (100%) delete mode 100644 app/src/main/res/layout-h600dp/item_detail_header.xml rename app/src/main/res/{layout-w600dp/fragment_detail2.xml => layout-land/fragment_detail.xml} (100%) delete mode 100644 app/src/main/res/layout-land/item_detail_header.xml create mode 100644 app/src/main/res/layout-sw600dp/fragment_detail.xml delete mode 100644 app/src/main/res/layout-sw600dp/item_detail_header.xml delete mode 100644 app/src/main/res/layout-sw840dp/item_detail_header.xml delete mode 100644 app/src/main/res/layout/item_detail_header.xml diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index c80f1cda6..d14d75f8f 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -19,29 +19,24 @@ package org.oxycblt.auxio.detail import android.os.Bundle -import android.view.LayoutInflater -import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearSmoothScroller import dagger.hilt.android.AndroidEntryPoint import org.oxycblt.auxio.R -import org.oxycblt.auxio.databinding.FragmentDetail2Binding +import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.detail.list.AlbumDetailListAdapter import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment -import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent -import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.PlaylistDecision import org.oxycblt.auxio.music.PlaylistMessage import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.PlaybackDecision -import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collectImmediately @@ -58,25 +53,14 @@ import org.oxycblt.auxio.util.unlikelyToBeNull */ @AndroidEntryPoint class AlbumDetailFragment : DetailFragment() { - private val detailModel: DetailViewModel by activityViewModels() - override val listModel: ListViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - // Information about what album to display is initially within the navigation arguments // as a UID, as that is the only safe way to parcel an album. private val args: AlbumDetailFragmentArgs by navArgs() private val albumListAdapter = AlbumDetailListAdapter(this) - override fun onCreateBinding(inflater: LayoutInflater) = - FragmentDetail2Binding.inflate(inflater) - override fun getDetailListAdapter() = albumListAdapter - override fun getSelectionToolbar(binding: FragmentDetail2Binding) = - binding.detailSelectionToolbar - - override fun onBindingCreated(binding: FragmentDetail2Binding, savedInstanceState: Bundle?) { + override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) { super.onBindingCreated(binding, savedInstanceState) // -- VIEWMODEL SETUP --- @@ -94,7 +78,7 @@ class AlbumDetailFragment : DetailFragment() { collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision) } - override fun onDestroyBinding(binding: FragmentDetail2Binding) { + override fun onDestroyBinding(binding: FragmentDetailBinding) { super.onDestroyBinding(binding) // Avoid possible race conditions that could cause a bad replace instruction to be consumed // during list initialization and crash the app. Could happen if the user is fast enough. diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index af65b9a27..4ea8ffb73 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -19,31 +19,25 @@ package org.oxycblt.auxio.detail import android.os.Bundle -import android.view.LayoutInflater import androidx.core.view.isVisible -import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import com.google.android.material.transition.MaterialSharedAxis import dagger.hilt.android.AndroidEntryPoint import org.oxycblt.auxio.R -import org.oxycblt.auxio.databinding.FragmentDetail2Binding +import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.detail.list.ArtistDetailListAdapter import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment -import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent -import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.PlaylistDecision import org.oxycblt.auxio.music.PlaylistMessage import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.PlaybackDecision -import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.context @@ -60,35 +54,14 @@ import org.oxycblt.auxio.util.unlikelyToBeNull */ @AndroidEntryPoint class ArtistDetailFragment : DetailFragment() { - private val detailModel: DetailViewModel by activityViewModels() - override val listModel: ListViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - // Information about what artist to display is initially within the navigation arguments // as a UID, as that is the only safe way to parcel an artist. private val args: ArtistDetailFragmentArgs by navArgs() private val artistListAdapter = ArtistDetailListAdapter(this) - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - // Detail transitions are always on the X axis. Shared element transitions are more - // semantically correct, but are also too buggy to be sensible. - enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - } - - override fun onCreateBinding(inflater: LayoutInflater) = - FragmentDetail2Binding.inflate(inflater) - - override fun getSelectionToolbar(binding: FragmentDetail2Binding) = - binding.detailSelectionToolbar - override fun getDetailListAdapter() = artistListAdapter - override fun onBindingCreated(binding: FragmentDetail2Binding, savedInstanceState: Bundle?) { + override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) { super.onBindingCreated(binding, savedInstanceState) // --- VIEWMODEL SETUP --- @@ -106,7 +79,7 @@ class ArtistDetailFragment : DetailFragment() { collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision) } - override fun onDestroyBinding(binding: FragmentDetail2Binding) { + override fun onDestroyBinding(binding: FragmentDetailBinding) { super.onDestroyBinding(binding) // Avoid possible race conditions that could cause a bad replace instruction to be consumed // during list initialization and crash the app. Could happen if the user is fast enough. diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt index 334142172..5213f08b0 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt @@ -22,7 +22,6 @@ import android.os.Bundle import android.view.LayoutInflater import androidx.fragment.app.activityViewModels import androidx.navigation.findNavController -import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.appbar.AppBarLayout import com.google.android.material.transition.MaterialSharedAxis @@ -30,7 +29,7 @@ import kotlin.math.abs import kotlin.math.max import kotlin.math.min import org.oxycblt.auxio.R -import org.oxycblt.auxio.databinding.FragmentDetail2Binding +import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.detail.list.DetailListAdapter import org.oxycblt.auxio.list.Divider import org.oxycblt.auxio.list.Header @@ -45,10 +44,10 @@ import org.oxycblt.auxio.util.overrideOnOverflowMenuClick import org.oxycblt.auxio.util.setFullWidthLookup abstract class DetailFragment

: - ListFragment(), + ListFragment(), DetailListAdapter.Listener, AppBarLayout.OnOffsetChangedListener { - private val detailModel: DetailViewModel by activityViewModels() + protected val detailModel: DetailViewModel by activityViewModels() override val listModel: ListViewModel by activityViewModels() override val musicModel: MusicViewModel by activityViewModels() override val playbackModel: PlaybackViewModel by activityViewModels() @@ -65,15 +64,14 @@ abstract class DetailFragment

: reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) } - override fun onCreateBinding(inflater: LayoutInflater) = - FragmentDetail2Binding.inflate(inflater) + override fun onCreateBinding(inflater: LayoutInflater) = FragmentDetailBinding.inflate(inflater) abstract fun getDetailListAdapter(): DetailListAdapter - override fun getSelectionToolbar(binding: FragmentDetail2Binding) = + override fun getSelectionToolbar(binding: FragmentDetailBinding) = binding.detailSelectionToolbar - override fun onBindingCreated(binding: FragmentDetail2Binding, savedInstanceState: Bundle?) { + override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) { super.onBindingCreated(binding, savedInstanceState) // --- UI SETUP --- @@ -103,7 +101,7 @@ abstract class DetailFragment

: spacingSmall = requireContext().getDimenPixels(R.dimen.spacing_small) } - override fun onDestroyBinding(binding: FragmentDetail2Binding) { + override fun onDestroyBinding(binding: FragmentDetailBinding) { super.onDestroyBinding(binding) binding.detailAppbar.removeOnOffsetChangedListener(this) binding.detailNormalToolbar.setOnMenuItemClickListener(null) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index 8938328e9..ec65f97bd 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -20,28 +20,23 @@ package org.oxycblt.auxio.detail import android.os.Bundle import androidx.core.view.isVisible -import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import com.google.android.material.transition.MaterialSharedAxis import dagger.hilt.android.AndroidEntryPoint import org.oxycblt.auxio.R -import org.oxycblt.auxio.databinding.FragmentDetail2Binding +import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.detail.list.GenreDetailListAdapter import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment -import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent -import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.PlaylistDecision import org.oxycblt.auxio.music.PlaylistMessage import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackDecision -import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.getPlural @@ -57,27 +52,14 @@ import org.oxycblt.auxio.util.unlikelyToBeNull */ @AndroidEntryPoint class GenreDetailFragment : DetailFragment() { - private val detailModel: DetailViewModel by activityViewModels() - override val listModel: ListViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - // Information about what genre to display is initially within the navigation arguments // as a UID, as that is the only safe way to parcel an genre. private val args: GenreDetailFragmentArgs by navArgs() private val genreListAdapter = GenreDetailListAdapter(this) - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - } - override fun getDetailListAdapter() = genreListAdapter - override fun onBindingCreated(binding: FragmentDetail2Binding, savedInstanceState: Bundle?) { + override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) { super.onBindingCreated(binding, savedInstanceState) // --- VIEWMODEL SETUP --- @@ -95,7 +77,7 @@ class GenreDetailFragment : DetailFragment() { collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision) } - override fun onDestroyBinding(binding: FragmentDetail2Binding) { + override fun onDestroyBinding(binding: FragmentDetailBinding) { super.onDestroyBinding(binding) // Avoid possible race conditions that could cause a bad replace instruction to be consumed // during list initialization and crash the app. Could happen if the user is fast enough. diff --git a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt index 6693e3bfd..b5f1fb8e9 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt @@ -23,31 +23,26 @@ import android.view.MenuItem import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible -import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.transition.MaterialSharedAxis import dagger.hilt.android.AndroidEntryPoint import org.oxycblt.auxio.R -import org.oxycblt.auxio.databinding.FragmentDetail2Binding +import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.detail.list.PlaylistDetailListAdapter import org.oxycblt.auxio.detail.list.PlaylistDragCallback import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment -import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent -import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.PlaylistDecision import org.oxycblt.auxio.music.PlaylistMessage import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.external.M3U import org.oxycblt.auxio.playback.PlaybackDecision -import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.DialogAwareNavigationListener import org.oxycblt.auxio.util.collect @@ -68,10 +63,6 @@ import org.oxycblt.auxio.util.unlikelyToBeNull @AndroidEntryPoint class PlaylistDetailFragment : DetailFragment(), PlaylistDetailListAdapter.Listener { - private val detailModel: DetailViewModel by activityViewModels() - override val listModel: ListViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() // Information about what playlist to display is initially within the navigation arguments // as a UID, as that is the only safe way to parcel an playlist. private val args: PlaylistDetailFragmentArgs by navArgs() @@ -81,17 +72,9 @@ class PlaylistDetailFragment : private var getContentLauncher: ActivityResultLauncher? = null private var pendingImportTarget: Playlist? = null - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - } - override fun getDetailListAdapter() = playlistListAdapter - override fun onBindingCreated(binding: FragmentDetail2Binding, savedInstanceState: Bundle?) { + override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) { super.onBindingCreated(binding, savedInstanceState) editNavigationListener = DialogAwareNavigationListener(detailModel::dropPlaylistEdit) @@ -114,13 +97,10 @@ class PlaylistDetailFragment : setOnMenuItemClickListener(this@PlaylistDetailFragment) } - binding.detailRecycler.apply { - adapter = playlistListAdapter - touchHelper = - ItemTouchHelper(PlaylistDragCallback(detailModel)).also { - it.attachToRecyclerView(this) - } - } + touchHelper = + ItemTouchHelper(PlaylistDragCallback(detailModel)).also { + it.attachToRecyclerView(binding.detailRecycler) + } // --- VIEWMODEL SETUP --- // DetailViewModel handles most initialization from the navigation argument. @@ -166,7 +146,7 @@ class PlaylistDetailFragment : .release(findNavController()) } - override fun onDestroyBinding(binding: FragmentDetail2Binding) { + override fun onDestroyBinding(binding: FragmentDetailBinding) { super.onDestroyBinding(binding) binding.detailNormalToolbar.setOnMenuItemClickListener(null) touchHelper = null diff --git a/app/src/main/res/layout/fragment_detail2.xml b/app/src/main/res/layout-h480dp/fragment_detail.xml similarity index 100% rename from app/src/main/res/layout/fragment_detail2.xml rename to app/src/main/res/layout-h480dp/fragment_detail.xml diff --git a/app/src/main/res/layout-h600dp/item_detail_header.xml b/app/src/main/res/layout-h600dp/item_detail_header.xml deleted file mode 100644 index cdaf0e484..000000000 --- a/app/src/main/res/layout-h600dp/item_detail_header.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout-w600dp/fragment_detail2.xml b/app/src/main/res/layout-land/fragment_detail.xml similarity index 100% rename from app/src/main/res/layout-w600dp/fragment_detail2.xml rename to app/src/main/res/layout-land/fragment_detail.xml diff --git a/app/src/main/res/layout-land/item_detail_header.xml b/app/src/main/res/layout-land/item_detail_header.xml deleted file mode 100644 index 432f6dc3e..000000000 --- a/app/src/main/res/layout-land/item_detail_header.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout-sw600dp/fragment_detail.xml b/app/src/main/res/layout-sw600dp/fragment_detail.xml new file mode 100644 index 000000000..53bd566bd --- /dev/null +++ b/app/src/main/res/layout-sw600dp/fragment_detail.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-sw600dp/item_detail_header.xml b/app/src/main/res/layout-sw600dp/item_detail_header.xml deleted file mode 100644 index 4b354bc58..000000000 --- a/app/src/main/res/layout-sw600dp/item_detail_header.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-sw840dp/item_detail_header.xml b/app/src/main/res/layout-sw840dp/item_detail_header.xml deleted file mode 100644 index d66af44bb..000000000 --- a/app/src/main/res/layout-sw840dp/item_detail_header.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_detail.xml b/app/src/main/res/layout/fragment_detail.xml index 8d46398f8..b94cec508 100644 --- a/app/src/main/res/layout/fragment_detail.xml +++ b/app/src/main/res/layout/fragment_detail.xml @@ -2,52 +2,179 @@ - - + android:layout_height="match_parent" + app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" + app:titleEnabled="false" + app:toolbarId="@+id/detail_toolbar"> - + + + + + + + + + + + + + + + + + + android:layout_gravity="bottom" + app:layout_collapseMode="pin" /> - + app:layout_collapseMode="pin" > - + - - + + + + + + + + + + + + + + + + + + tools:listitem="@layout/item_song" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_detail_header.xml b/app/src/main/res/layout/item_detail_header.xml deleted file mode 100644 index 0ea6a4111..000000000 --- a/app/src/main/res/layout/item_detail_header.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - -