diff --git a/app/build.gradle b/app/build.gradle index 9bb293e..5b5890e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,17 @@ plugins { id 'com.android.application' id 'kotlin-android' + id 'kotlin-parcelize' + id 'androidx.navigation.safeargs.kotlin' } android { - compileSdk 30 + compileSdk 31 defaultConfig { applicationId "com.itis.androidlabproject" minSdk 23 - targetSdk 30 + targetSdk 31 versionCode 1 versionName "1.0" @@ -36,13 +38,25 @@ android { } dependencies { + // Navigation + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' - implementation 'androidx.core:core-ktx:1.6.0' + //Glide + implementation 'com.github.bumptech.glide:glide:4.12.0' + implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.2" + + implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.1' - implementation 'android.arch.navigation:navigation-fragment:2.3.5' - implementation 'android.arch.navigation:navigation-ui:2.3.5' + + implementation 'androidx.recyclerview:recyclerview:1.2.1' + + implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' + implementation 'de.hdodenhof:circleimageview:3.1.0' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' + testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 69ebd0a..c1e31fd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + + diff --git a/app/src/main/java/com/itis/androidlabproject/MainActivity.kt b/app/src/main/java/com/itis/androidlabproject/MainActivity.kt deleted file mode 100644 index d85e6eb..0000000 --- a/app/src/main/java/com/itis/androidlabproject/MainActivity.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.itis.androidlabproject - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle - -class MainActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/itis/androidlabproject/activity/MainActivity.kt b/app/src/main/java/com/itis/androidlabproject/activity/MainActivity.kt new file mode 100644 index 0000000..47d6b65 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/activity/MainActivity.kt @@ -0,0 +1,25 @@ +package com.itis.androidlabproject.activity + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.NavController +import androidx.navigation.ui.setupWithNavController +import com.itis.androidlabproject.R +import com.itis.androidlabproject.databinding.ActivityMainBinding +import com.itis.androidlabproject.extension.findNavController + +class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + private lateinit var navController: NavController + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater).also { + setContentView(it.root) + } + + navController = findNavController(R.id.fragment_container) + + binding.btnNavView.setupWithNavController(navController) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/PlanetAdapter.kt b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetAdapter.kt new file mode 100644 index 0000000..8ad3f6b --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetAdapter.kt @@ -0,0 +1,34 @@ +package com.itis.androidlabproject.adapter + +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.RequestManager +import com.itis.androidlabproject.model.Planet + +class PlanetAdapter( + private val list: ArrayList, + private val glide: RequestManager, + private val action: (Int) -> Unit +) : RecyclerView.Adapter() { + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): PlanetHolder = PlanetHolder.create(parent, glide, action) + + override fun onBindViewHolder(holder: PlanetHolder, position: Int) { + holder.bind(list[position]) + } + + override fun getItemCount(): Int = list.size; + + fun updateData(newData: List) { + val callback = PlanetDiffUtils(list, newData) + val diffResult = DiffUtil.calculateDiff(callback) + diffResult.dispatchUpdatesTo(this) + + list.clear() + list.addAll(newData) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/PlanetCardViewAdapter.kt b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetCardViewAdapter.kt new file mode 100644 index 0000000..9e8b150 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetCardViewAdapter.kt @@ -0,0 +1,23 @@ +package com.itis.androidlabproject.adapter + +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.RequestManager +import com.itis.androidlabproject.model.Planet + +class PlanetCardViewAdapter( + private val list: List, + private val glide: RequestManager, +) : RecyclerView.Adapter() { + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): PlanetCardViewHolder = PlanetCardViewHolder.create(parent, glide) + + override fun onBindViewHolder(holder: PlanetCardViewHolder, position: Int) { + holder.bind(list[position]) + } + + override fun getItemCount(): Int = list.size +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/PlanetCardViewHolder.kt b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetCardViewHolder.kt new file mode 100644 index 0000000..2766d99 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetCardViewHolder.kt @@ -0,0 +1,52 @@ +package com.itis.androidlabproject.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Priority +import com.bumptech.glide.RequestManager +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.RequestOptions +import com.itis.androidlabproject.databinding.ItemCvPlanetBinding +import com.itis.androidlabproject.model.Planet + +class PlanetCardViewHolder( + private val binding: ItemCvPlanetBinding, + private val glide: RequestManager, +) : RecyclerView.ViewHolder(binding.root) { + + private var album: Planet? = null + + private val options = RequestOptions() + .priority(Priority.HIGH) + .diskCacheStrategy(DiskCacheStrategy.ALL) + + fun bind(item: Planet) { + this.album = item + with(binding) { + tvName1.text = item.name + tvName2.text = item.name + tvNumberOfSatellite.text = "Количество спутников: ${item.numberOfSatellite}" + tvDesc.text = item.description + + glide.load(item.url) + .apply(options) + .into(ivImage1) + vp2Images.adapter = ViewPagerAdapter(item.url, glide) + } + + } + + companion object { + fun create( + parent: ViewGroup, + glide: RequestManager, + ) = PlanetCardViewHolder( + ItemCvPlanetBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), glide + ) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/PlanetDiffItemCallback.kt b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetDiffItemCallback.kt new file mode 100644 index 0000000..a1ecd29 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetDiffItemCallback.kt @@ -0,0 +1,36 @@ +package com.itis.androidlabproject.adapter + +import android.os.Bundle +import androidx.recyclerview.widget.DiffUtil +import com.itis.androidlabproject.model.Planet + +class PlanetDiffItemCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: Planet, + newItem: Planet + ): Boolean = oldItem.id == newItem.id + + override fun areContentsTheSame( + oldItem: Planet, + newItem: Planet + ): Boolean = oldItem == newItem + + override fun getChangePayload(oldItem: Planet, newItem: Planet): Any? { + var bundle = Bundle() + + if (oldItem.name != newItem.name) { + bundle.putString("NAME", newItem.name) + } + if (oldItem.numberOfSatellite != newItem.numberOfSatellite) { + bundle.putInt("NUMBER_OF_SATELLITE", newItem.numberOfSatellite) + } + if (oldItem.description != newItem.description) { + bundle.putString("DESCRIPTION", newItem.description) + } + if (oldItem.url != newItem.url) { + bundle.putString("URL", newItem.url) + } + if (bundle.isEmpty) return null + return bundle + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/PlanetDiffUtils.kt b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetDiffUtils.kt new file mode 100644 index 0000000..0516b8d --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetDiffUtils.kt @@ -0,0 +1,49 @@ +package com.itis.androidlabproject.adapter + +import android.os.Bundle +import androidx.core.os.bundleOf +import androidx.recyclerview.widget.DiffUtil +import com.itis.androidlabproject.model.Planet + +class PlanetDiffUtils( + private var oldList: List, + private var newList: List +) : DiffUtil.Callback() { + override fun getOldListSize(): Int = oldList.size + + override fun getNewListSize(): Int = newList.size + + override fun areItemsTheSame( + oldItemPosition: Int, + newItemPosition: Int, + ): Boolean = + oldList[oldItemPosition].id == newList[newItemPosition].id + + override fun areContentsTheSame( + oldItemPosition: Int, + newItemPosition: Int, + ): Boolean = oldList[oldItemPosition] == newList[newItemPosition] + + override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { + var oldPlanet = oldList[oldItemPosition] + var newPlanet = newList[newItemPosition] + + var bundle = Bundle() + + if (oldPlanet.name != newPlanet.name) { + bundle.putString("NAME", newPlanet.name) + } + if (oldPlanet.numberOfSatellite != newPlanet.numberOfSatellite) { + bundle.putInt("NUMBER_OF_SATELLITE", newPlanet.numberOfSatellite) + } + if (oldPlanet.description != newPlanet.description) { + bundle.putString("DESCRIPTION", newPlanet.description) + } + if (oldPlanet.url != newPlanet.url) { + bundle.putString("URL", newPlanet.url) + } + if (bundle.isEmpty) return null + + return bundle + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/PlanetHolder.kt b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetHolder.kt new file mode 100644 index 0000000..824f8f5 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetHolder.kt @@ -0,0 +1,87 @@ +package com.itis.androidlabproject.adapter + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Priority +import com.bumptech.glide.RequestManager +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.RequestOptions +import com.itis.androidlabproject.databinding.ItemPlanetBinding +import com.itis.androidlabproject.model.Planet +import com.itis.androidlabproject.repository.PlanetRepository + +class PlanetHolder( + private val binding: ItemPlanetBinding, + private val glide: RequestManager, + private val action: (Int) -> Unit +) : RecyclerView.ViewHolder(binding.root) { + private var planet: Planet? = null + + private val options = RequestOptions() + .priority(Priority.HIGH) + .diskCacheStrategy(DiskCacheStrategy.ALL) + +// init { +// itemView.setOnClickListener { +// planet?.run { +// action(this.id) +// } +// } +// } + + @SuppressLint("SetTextI18n") + fun bind(item: Planet) { + this.planet = item + with(binding) { + tvDetName.text = item.name + tvNumberOfSatellite.text = "Количество спутников: ${item.numberOfSatellite}" + + glide.load(item.url) + .apply(options) + .into(ivImage) + + btnDelete.setOnClickListener { + action(PlanetRepository.getIndex(item)) + } + } + } + + fun updateFields(bundle: Bundle) { + bundle.run { + getString("NAME")?.also { + updateName(it) + } + getInt("NUMBER_OF_SATELLITE").also { + updateNumberOfSatellite(it) + } + } + } + + fun updateName(newName: String) { + binding.tvDetName.text = newName + } + + @SuppressLint("SetTextI18n") + fun updateNumberOfSatellite(newNumberOfSatellite: Int) { + binding.tvNumberOfSatellite.text = "Количество спутников: $newNumberOfSatellite" + } + + companion object { + fun create( + parent: ViewGroup, + glide: RequestManager, + action: (Int) -> Unit + ) = PlanetHolder( + ItemPlanetBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), + glide, + action + ) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/PlanetListAdapter.kt b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetListAdapter.kt new file mode 100644 index 0000000..3f13758 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/PlanetListAdapter.kt @@ -0,0 +1,44 @@ +package com.itis.androidlabproject.adapter + +import android.os.Bundle +import android.view.ViewGroup +import androidx.recyclerview.widget.ListAdapter +import com.bumptech.glide.RequestManager +import com.itis.androidlabproject.model.Planet +import java.util.ArrayList + +class PlanetListAdapter( + private val glide: RequestManager, + private val action: (Int) -> Unit +) : ListAdapter(PlanetDiffItemCallback()) { + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): PlanetHolder = PlanetHolder.create(parent, glide, action) + + override fun onBindViewHolder( + holder: PlanetHolder, + position: Int + ) { + holder.bind(getItem(position)) + } + + override fun onBindViewHolder( + holder: PlanetHolder, + position: Int, + payloads: MutableList + ) { + if (payloads.isEmpty()) { + super.onBindViewHolder(holder, position, payloads) + } else { + payloads.last().takeIf { it is Bundle }?.let { + holder.updateFields(it as Bundle) + } + } + } + + override fun submitList(list: MutableList?) { + super.submitList(if (list == null) null else ArrayList(list)) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/SwipeToDelete.kt b/app/src/main/java/com/itis/androidlabproject/adapter/SwipeToDelete.kt new file mode 100644 index 0000000..f10e3b8 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/SwipeToDelete.kt @@ -0,0 +1,14 @@ +package com.itis.androidlabproject.adapter + +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView + +abstract class SwipeToDelete : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + return false + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/ViewPagerAdapter.kt b/app/src/main/java/com/itis/androidlabproject/adapter/ViewPagerAdapter.kt new file mode 100644 index 0000000..3284ca2 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/ViewPagerAdapter.kt @@ -0,0 +1,40 @@ +package com.itis.androidlabproject.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.RequestManager +import com.itis.androidlabproject.databinding.ItemViewpagerBinding + + +class ViewPagerAdapter( + private val url: String, + private val glide: RequestManager, +) : RecyclerView.Adapter() { + + + inner class ViewPagerViewHolder( + private val binding: ItemViewpagerBinding, + ) : RecyclerView.ViewHolder(binding.root) { + + fun bind(pos: Int) { + with(binding) { + glide.load(url).into(ivImage) + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerViewHolder { + return ViewPagerViewHolder( + ItemViewpagerBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + ) + } + + override fun onBindViewHolder(holder: ViewPagerViewHolder, position: Int) { + holder.bind(position) + } + + override fun getItemCount() = 1 +} diff --git a/app/src/main/java/com/itis/androidlabproject/decorator/SpaceItemDecorator.kt b/app/src/main/java/com/itis/androidlabproject/decorator/SpaceItemDecorator.kt new file mode 100644 index 0000000..072a6f6 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/decorator/SpaceItemDecorator.kt @@ -0,0 +1,45 @@ +package com.itis.androidlabproject.decorator + +import android.content.Context +import android.graphics.Rect +import android.util.TypedValue +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +class SpaceItemDecorator( + context: Context, + spacing: Float = 16f, +) : RecyclerView.ItemDecoration() { + + private val spacingPx: Int = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + spacing, + context.resources.displayMetrics + ).toInt() + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + val position = parent.getChildAdapterPosition(view) + val spacingMiddle: Int = spacingPx / 2 + when (position) { + 0 -> { + outRect.top = spacingPx + outRect.bottom = spacingMiddle + } + state.itemCount - 1 -> { + outRect.top = spacingMiddle + outRect.bottom = spacingPx + } + else -> { + outRect.top = spacingMiddle + outRect.bottom = spacingMiddle + } + } + outRect.left = spacingPx + outRect.right = spacingPx + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/dialogs/AddDialog.kt b/app/src/main/java/com/itis/androidlabproject/dialogs/AddDialog.kt new file mode 100644 index 0000000..a30acb1 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/dialogs/AddDialog.kt @@ -0,0 +1,60 @@ +package com.example.androidsemthree.dialogs + +import android.app.AlertDialog +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager +import com.itis.androidlabproject.databinding.DialogAddBinding + +class AddDialog : DialogFragment() { + private lateinit var binding: DialogAddBinding + + var positiveCallBack: ((Array) -> Unit)? = null + var positiveNotFullCallBack: ((Boolean) -> Unit)? = null + + override fun onCreateDialog( + savedInstanceState: Bundle? + ): Dialog = AlertDialog.Builder(requireContext()) + .setView(DialogAddBinding.inflate(layoutInflater).let { + binding = it + it.root + }) + .setTitle("Добавление планеты") + .setMessage("Введите данные") + .setPositiveButton("OK") { _, _ -> + var flag = false; + val name = binding.etName.text?.toString() ?: "" + val desc = binding.etDescription.text?.toString() ?: "" + val pos = binding.etPosition.text?.toString() ?: "" + val numberOfSatellite = binding.etDetNumberOfSatellite.text?.toString() ?: "0" + if (name.isNotEmpty()) { + if (desc.isNotEmpty()) { + flag = true + val array = arrayOf(name, numberOfSatellite, desc, pos) + positiveCallBack?.invoke(array) + } + } + if (!flag) { + positiveNotFullCallBack?.invoke(flag) + } + } + .setNegativeButton("Cancel") { dialog, _ -> + dialog.dismiss() + }.create() + + companion object { + fun show( + fragmentManager: FragmentManager, + positive: (Array) -> Unit, + notFull: (Boolean) -> Unit + ) { + AddDialog().apply { + positiveNotFullCallBack = notFull + positiveCallBack = positive + show(fragmentManager, AddDialog::class.java.name) + } + } + } +} + diff --git a/app/src/main/java/com/itis/androidlabproject/extension/ActivityExt.kt b/app/src/main/java/com/itis/androidlabproject/extension/ActivityExt.kt new file mode 100644 index 0000000..8fc4c5c --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/extension/ActivityExt.kt @@ -0,0 +1,9 @@ +package com.itis.androidlabproject.extension + +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.NavController +import androidx.navigation.fragment.NavHostFragment + +fun AppCompatActivity.findNavController(id: Int): NavController { + return (supportFragmentManager.findFragmentById(id) as NavHostFragment).navController +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragment/CardViewFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragment/CardViewFragment.kt new file mode 100644 index 0000000..0da1383 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragment/CardViewFragment.kt @@ -0,0 +1,45 @@ +package com.itis.androidlabproject.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.itis.androidlabproject.R +import com.itis.androidlabproject.adapter.PlanetCardViewAdapter +import com.itis.androidlabproject.databinding.FragmentCardBinding +import com.itis.androidlabproject.decorator.SpaceItemDecorator +import com.itis.androidlabproject.repository.PlanetRepository + +class CardViewFragment : Fragment() { + private lateinit var binding: FragmentCardBinding + private lateinit var albumCardViewAdapter: PlanetCardViewAdapter + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentCardBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + albumCardViewAdapter = PlanetCardViewAdapter(PlanetRepository.planets, Glide.with(this)) + + val decorator = DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) + val spacing = SpaceItemDecorator(requireContext()) + + with(binding) { + rvPlanets.run { + adapter = albumCardViewAdapter + addItemDecoration(decorator) + addItemDecoration(spacing) + } + } + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragment/DetailsFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragment/DetailsFragment.kt new file mode 100644 index 0000000..d205520 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragment/DetailsFragment.kt @@ -0,0 +1,50 @@ +package com.itis.androidlabproject.fragment + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.bumptech.glide.Glide +import com.itis.androidlabproject.R +import com.itis.androidlabproject.databinding.FragmentDetailsBinding +import com.itis.androidlabproject.model.Planet +import com.itis.androidlabproject.repository.PlanetRepository + +class DetailsFragment : Fragment(R.layout.fragment_details) { + private lateinit var binding: FragmentDetailsBinding + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.run { + arguments?.getInt("planetId")?.let { planetId -> + PlanetRepository.getPlanetById(planetId).let { + showChosenPlanet(it) + } + } + } + + } + + @SuppressLint("SetTextI18n") + private fun showChosenPlanet(planet: Planet) { + with(binding) { + Glide.with(this.root).load(planet.url).into(ivPhoto) + tvDetName.text = "Название планеты: ${planet.name}" + tvDetNumberOfSatellite.text = "Количество спутников ${planet.numberOfSatellite}" + tvDetDescription.text = "Описание: ${planet.description}" + collapsingToolbar.title = planet.name + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentDetailsBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragment/FirstFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragment/FirstFragment.kt new file mode 100644 index 0000000..c9628d0 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragment/FirstFragment.kt @@ -0,0 +1,7 @@ +package com.itis.androidlabproject.fragment + +import androidx.fragment.app.Fragment +import com.itis.androidlabproject.R + +class FirstFragment : Fragment(R.layout.fragment_first) { +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragment/ListFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragment/ListFragment.kt new file mode 100644 index 0000000..065f534 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragment/ListFragment.kt @@ -0,0 +1,127 @@ +package com.itis.androidlabproject.fragment + +import android.os.Bundle +import android.view.View +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.navigation.NavOptions +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.example.androidsemthree.dialogs.AddDialog +import com.google.android.material.snackbar.Snackbar +import com.itis.androidlabproject.R +import com.itis.androidlabproject.adapter.PlanetListAdapter +import com.itis.androidlabproject.adapter.SwipeToDelete +import com.itis.androidlabproject.databinding.FragmentListBinding +import com.itis.androidlabproject.decorator.SpaceItemDecorator +import com.itis.androidlabproject.repository.PlanetRepository + +class ListFragment : Fragment(R.layout.fragment_list) { + private var binding: FragmentListBinding? = null + private var planetListAdapter: PlanetListAdapter? = null + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle? + ) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentListBinding.bind(view) + + planetListAdapter = PlanetListAdapter(Glide.with(this)) { +// showPlanetDetails(it) + PlanetRepository.delete(it) + refresh() + } + + val decorator = DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) + val spacing = SpaceItemDecorator(requireContext(), 24f) + binding?.run { + rvPlanets.run { + adapter = planetListAdapter + addItemDecoration(decorator) + addItemDecoration(spacing) + swipeToDelete(this) + } + refresh() + btnAdd.setOnClickListener { + showDialog() + } + + } + + planetListAdapter?.submitList(PlanetRepository.planets) + } + + private fun refresh() { + planetListAdapter?.submitList(PlanetRepository.planets) { + binding?.rvPlanets?.scrollToPosition(0); + } + } + + private fun showPlanetDetails(id: Int) { + val bundle = bundleOf( + "planetId" to id + ) + + val options = NavOptions.Builder() + .setLaunchSingleTop(false) + .setEnterAnim(R.anim.enter_from_right) + .setExitAnim(R.anim.fade_out) + .setPopEnterAnim(R.anim.fade_in) + .setPopExitAnim(R.anim.exit_to_right) + .build() + findNavController().navigate(R.id.action_listFragment_to_detailsFragment, bundle, options) + } + + private fun swipeToDelete(recyclerView: RecyclerView) { + val swipeToDeleteCallback = object : SwipeToDelete() { + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val item = planetListAdapter?.currentList?.get(viewHolder.absoluteAdapterPosition) + PlanetRepository.delete(item) + refresh() + } + } + val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallback) + itemTouchHelper.attachToRecyclerView(recyclerView) + } + + private fun showDialog() { + AddDialog.show( + childFragmentManager, + positive = { positiveAddDialog(it) }, + notFull = { notFullAlert(it) }) + } + + private fun positiveAddDialog(array: Array) { + val name = array[0] + val numberOfSatellite = Integer.parseInt(array[1]) + val desc = array[2] + val pos: Int? = if (array[3].isEmpty()) { + null + } else { + array[3].toInt() + } + PlanetRepository.add(pos, name, numberOfSatellite, desc) + refresh() + } + + private fun notFullAlert(flag: Boolean) { + if (!flag) { + binding?.root?.let { + Snackbar.make( + it, + "Please, enter all data and try again", + Snackbar.LENGTH_LONG + ).show() + } + } + } + + override fun onDestroyView() { + super.onDestroyView() + binding = null + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/model/Planet.kt b/app/src/main/java/com/itis/androidlabproject/model/Planet.kt new file mode 100644 index 0000000..0d874fd --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/model/Planet.kt @@ -0,0 +1,9 @@ +package com.itis.androidlabproject.model + +data class Planet( + var id: Int, + var name: String, + val numberOfSatellite: Int = 0, + var url: String, + var description: String +) diff --git a/app/src/main/java/com/itis/androidlabproject/repository/PlanetRepository.kt b/app/src/main/java/com/itis/androidlabproject/repository/PlanetRepository.kt new file mode 100644 index 0000000..f8aeda6 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/repository/PlanetRepository.kt @@ -0,0 +1,106 @@ +package com.itis.androidlabproject.repository + +import android.media.Image +import com.itis.androidlabproject.model.Planet + +object PlanetRepository { + var autoUrl = "https://cosmos.agency/wp-content/uploads/2015/08/pluto_heart_colored.png" + var autoIncId = 0; + val planets = arrayListOf( + Planet( + id = autoIncId++, + name = "Меркурий", + url = "https://cosmos.agency/wp-content/uploads/2015/08/pluto_heart_colored.png", + description = "Меркурий — самая близкая к Солнцу планета Солнечной системы, обращающаяся вокруг Солнца за 88 земных суток. Продолжительность одних звёздных суток на Меркурии составляет 58,65 земных[, а солнечных — 176 земных. Планета названа в честь древнеримского бога торговли — быстроногого Меркурия, поскольку она движется по небу быстрее других планет. Меркурий относится к планетам земной группы. После лишения Плутона в 2006 году статуса планеты к Меркурию перешло звание самой маленькой планеты Солнечной системы. Снимок сделан межпланетной станцией «Мессенджер»" + ), + Planet( + id = autoIncId++, + name = "Венера", + url = "https://cosmos.agency/wp-content/uploads/2015/08/venus_magellan.png", + description = "Венера — самая горячая планета Солнечной системы. В глубокой древности Венера, как полагают, настолько разогрелась, что подобные земным океаны, которыми, как считается, она обладала, полностью испарились, оставив после себя пустынный пейзаж с множеством плитоподобных скал. По структуре и размеру Венера подобна Земле. Ее толстая, токсичная атмосфера удерживает тепло, держа температуру поверхности достаточно горячей, для того, чтобы плавился свинец. Сфотографированна с межпланетной станции Магеллан." + ), + Planet( + id = autoIncId++, + name = "Земля", + numberOfSatellite = 1, + url = "https://cosmos.agency/wp-content/uploads/2015/08/earth.png", + description = "Земля — третья от Солнца планета. Пятая по размеру среди всех планет Солнечной системы. Она является также крупнейшей по диаметру, массе и плотности среди планет земной группы. Мы все на ней живем." + ), + Planet( + id = autoIncId++, + name = "Марс", + numberOfSatellite = 2, + url = "https://cosmos.agency/wp-content/uploads/2015/08/mars-globe-valles-marineris-enhanced-800.png", + description = "Марс — четвёртая по удалённости от Солнца (после Меркурия, Венеры и Земли) и седьмая по размерам планета Солнечной системы. Рельеф Марса обладает многими уникальными чертами. Марсианский потухший вулкан гора Олимп — самая высокая известная гора на планетах Солнечной системы, а долины Маринер — самый крупный известный каньон. Долины имеют длину 4500 км (четверть окружности планеты), ширину — 200 км и глубину — до 11 км. Эта система каньонов превышает знаменитый Большой каньон в 10 раз по длине, в 7 — по ширине и в 7 — по глубине. Композитная фотография планеты Марс с видом на долины Маринер." + ), + Planet( + id = autoIncId++, + name = "Юпитер", + numberOfSatellite = 79, + url = "https://cosmos.agency/wp-content/uploads/2015/08/planet_jupiter_mid_cosmos_agency.png", + description = "Юпитер — пятая планета от Солнца, располагается между Марсом и Сатурном. Отдалена от Солнца на 778.5 миллионов километров. Газовый гигант (три других газовых гиганта: Сатурн, Уран, Нептун), самая большая планета в Солнечной системе. Сутки на Юпитере длятся почти 10 часов, а год — 4333 земных дней, т.е. 11,8 лет." + ), + Planet( + id = autoIncId++, + name = "Сатурн", + numberOfSatellite = 62, + url = "https://cosmos.agency/wp-content/uploads/2015/08/saturn.png", + description = "Украшенный тысячами красивых колец, Сатурн является уникальной планетой. Все четыре газовых гиганта (Нептун, Уран, Сатурн, Юпитер) имеют кольца из глыбин льда и камней, но только Сатурн может похвастаться такой зрелищностью. Как и другие газовые гиганты, Сатурн в основном состоит из водорода и гелия. Планета находится в 1430 млн км от солнца, в 10 раз дальше чем Земля. Вокруг планеты обращается 62 известных на данный момент спутника. Титан — самый крупный из них, а также второй по размерам спутник в Солнечной системе (после спутника Юпитера, Ганимеда), который превосходит по своим размерам Меркурий и обладает единственной среди спутников Солнечной системы плотной атмосферой. Этот портрет Сатурна и его колец скомпонован любителем и фанатом Кассини Горданом Угарковичем из изображений полученных с космического аппарата NASA Кассини 10 октября 2013." + ), + Planet( + id = autoIncId++, + name = "Уран", + numberOfSatellite = 0, + url = "https://cosmos.agency/wp-content/uploads/2015/08/768px-Uranus2.png", + description = "Уран — седьмая планета Солнечной системы по удалённости от Солнца, третья по диаметру и четвёртая по массе. Была открыта в 1781 году английским астрономом Уильямом Гершелем и названа в честь греческого бога неба Урана, отца Кроноса (в римской мифологии Сатурна) и, соответственно, деда Зевса (у римлян — Юпитер). Фотография планеты Уран сделанная космическим аппаратом «Вояджер-2» в 1986" + ), + Planet( + id = autoIncId++, + name = "Нептун", + numberOfSatellite = 0, + url = "https://cosmos.agency/wp-content/uploads/2015/08/neptune_800.png", + description = "Темная, холодная, овеваемая сверхзвуковыми ветрами, планета Нептун, состоит из водорода и гелия и является самой дальней из газовых гигантов в нашей солнечной системе. Она находится на расстоянии в 4.5 миллиарда километров (что в 30 раз дальше чем Земля) от Солнца. Один год на Нептуне длится 165 земных лет, в 2011 году завершился первый год с момента его открытия в 1846. Нептун — восьмая планета Солнечной системы. Нептун также является четвёртой по диаметру и третьей по массе планетой. Масса Нептуна в 17,2 раза, а диаметр экватора в 3,9 раза больше таковых у Земли. Планета была названа в честь римского бога морей. Фотография планеты Нептун. Сделана космическим аппаратом «Вояджер 2» в 1989" + ), + Planet( + id = autoIncId++, + name = "Плутон", + numberOfSatellite = 0, + url = "https://cosmos.agency/wp-content/uploads/2015/08/pluto_heart_colored.png", + description = "Плутон — крупнейшая по размеру известная карликовая планета Солнечной системы, транснептуновый объект (ТНО) и десятое по массе (без учёта спутников) небесное тело, обращающееся вокруг Солнца — после восьми планет Солнечной системы и Эриды. Первоначально Плутон классифицировался как классическая планета, однако сейчас он считается карликовой планетой и самым крупным объектом в поясе Койпера. Цветное изображение Плутона, полученное автоматической межпланетной станцией «Новые горизонты» 14 июля 2015 года с расстояния 450 000 км" + ), + Planet( + id = autoIncId++, + name = "Ио", + numberOfSatellite = 0, + url = "https://cosmos.agency/wp-content/uploads/2015/08/Io_highest_resolution_true_color1.png", + description = "Фото Ио, сделанное аппаратом «Галилео» в 1999 году. Желтоватый цвет говорит о высоком содержании серы. Тёмное пятно левее центра — извергающийся вулкан Прометей, его окружают светлые равнины, покрытые оксидом серы. Хоть Ио и спутник Юпитера и не подходит для нашей подборки фотографий планет (в т.ч. одной карликовой) Солнечной системы от NASA, он весьма необычен и заслуживает место в списке." + ) + ) + + fun getPlanetById(id: Int): Planet { + return this.planets[id] + } + + fun delete(id: Int) { + planets.removeAt(id) + } + + fun delete(planet: Planet?) { + planets.remove(planet) + } + + fun getIndex(planet: Planet) : Int { + return planets.indexOf(planet) + } + + fun add(pos: Int?, name: String, numberOfSatellite: Int, description: String) { + if (pos == null || pos > planets.size || pos < 0) { + planets.add(Planet(autoIncId++, name, numberOfSatellite, autoUrl, description)) + } else update(pos, name, description) + } + + fun update(pos: Int, name: String, description: String) { + planets[pos].name = name + planets[pos].description = description + } +} diff --git a/app/src/main/res/anim/enter_from_right.xml b/app/src/main/res/anim/enter_from_right.xml new file mode 100644 index 0000000..d424f42 --- /dev/null +++ b/app/src/main/res/anim/enter_from_right.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/anim/exit_to_right.xml b/app/src/main/res/anim/exit_to_right.xml new file mode 100644 index 0000000..7becffd --- /dev/null +++ b/app/src/main/res/anim/exit_to_right.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml new file mode 100644 index 0000000..2f74325 --- /dev/null +++ b/app/src/main/res/anim/fade_in.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml new file mode 100644 index 0000000..678a617 --- /dev/null +++ b/app/src/main/res/anim/fade_out.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/drawable/ic_round_delete.xml b/app/src/main/res/drawable/ic_round_delete.xml new file mode 100644 index 0000000..72870fe --- /dev/null +++ b/app/src/main/res/drawable/ic_round_delete.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/icon_add.xml b/app/src/main/res/drawable/icon_add.xml new file mode 100644 index 0000000..eb23254 --- /dev/null +++ b/app/src/main/res/drawable/icon_add.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/icon_cards.xml b/app/src/main/res/drawable/icon_cards.xml new file mode 100644 index 0000000..238ff4d --- /dev/null +++ b/app/src/main/res/drawable/icon_cards.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/icon_home.xml b/app/src/main/res/drawable/icon_home.xml new file mode 100644 index 0000000..3a4c7da --- /dev/null +++ b/app/src/main/res/drawable/icon_home.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/icon_list.xml b/app/src/main/res/drawable/icon_list.xml new file mode 100644 index 0000000..9884aeb --- /dev/null +++ b/app/src/main/res/drawable/icon_list.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4fa45b0..20731b2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,15 +4,28 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity"> + tools:context=".activity.MainActivity"> - + app:layout_constraintTop_toTopOf="parent" + app:navGraph="@navigation/nav_graph" /> + + diff --git a/app/src/main/res/layout/dialog_add.xml b/app/src/main/res/layout/dialog_add.xml new file mode 100644 index 0000000..9d9d446 --- /dev/null +++ b/app/src/main/res/layout/dialog_add.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_card.xml b/app/src/main/res/layout/fragment_card.xml new file mode 100644 index 0000000..1a8b89f --- /dev/null +++ b/app/src/main/res/layout/fragment_card.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml new file mode 100644 index 0000000..e571860 --- /dev/null +++ b/app/src/main/res/layout/fragment_details.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_first.xml b/app/src/main/res/layout/fragment_first.xml new file mode 100644 index 0000000..1d090cb --- /dev/null +++ b/app/src/main/res/layout/fragment_first.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_list.xml b/app/src/main/res/layout/fragment_list.xml new file mode 100644 index 0000000..548a560 --- /dev/null +++ b/app/src/main/res/layout/fragment_list.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_third.xml b/app/src/main/res/layout/fragment_third.xml new file mode 100644 index 0000000..1354408 --- /dev/null +++ b/app/src/main/res/layout/fragment_third.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/layout/item_cv_planet.xml b/app/src/main/res/layout/item_cv_planet.xml new file mode 100644 index 0000000..391b1fd --- /dev/null +++ b/app/src/main/res/layout/item_cv_planet.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_planet.xml b/app/src/main/res/layout/item_planet.xml new file mode 100644 index 0000000..02bb365 --- /dev/null +++ b/app/src/main/res/layout/item_planet.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_viewpager.xml b/app/src/main/res/layout/item_viewpager.xml new file mode 100644 index 0000000..9b819dd --- /dev/null +++ b/app/src/main/res/layout/item_viewpager.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml new file mode 100644 index 0000000..1905e99 --- /dev/null +++ b/app/src/main/res/menu/menu.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml new file mode 100644 index 0000000..35da2c4 --- /dev/null +++ b/app/src/main/res/navigation/nav_graph.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f931ae8..4ac4d6e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ AndroidLabProject - \ No newline at end of file + Название планеты + Количество спутников + diff --git a/build.gradle b/build.gradle index 12f1d4c..4afb132 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,9 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:7.0.2" + classpath 'com.android.tools.build:gradle:7.0.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30" + classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files