diff --git a/README.md b/README.md deleted file mode 100644 index 9acb3cb..0000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Лекции 2021 года - Осень - -Все презентации находятся в `presentation` - -## Запись лекций - -1) Лекция 11 - Тестирование и Дебаггинг ([Zoom](https://mailru.zoom.us/rec/share/XfMpXzH817exIlmUkuPxd9Y6Ty77WTf0d73uJGUrdFvXCVcR0eNAJGLmd4vOzATR.02j4j43OxycNk05D?startTime=1638371009000)) \ No newline at end of file diff --git a/lection02/.idea/.name b/lection02/.idea/.name deleted file mode 100644 index 2605bcd..0000000 --- a/lection02/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Lesson02 \ No newline at end of file diff --git a/lection02/.idea/codeStyles/Project.xml b/lection02/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..3c7772a --- /dev/null +++ b/lection02/.idea/codeStyles/Project.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/lection02/.idea/codeStyles/codeStyleConfig.xml b/lection02/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/lection02/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/lection02/app/src/main/java/com/mycompany/helloworld/HelloActivity.kt b/lection02/app/src/main/java/com/mycompany/helloworld/HelloActivity.kt new file mode 100644 index 0000000..2e268d6 --- /dev/null +++ b/lection02/app/src/main/java/com/mycompany/helloworld/HelloActivity.kt @@ -0,0 +1,70 @@ +package com.mycompany.helloworld + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.floatingactionbutton.FloatingActionButton + +class HelloActivity : AppCompatActivity() { + + private val movies = generateMovieList().toMutableList() + + var adapter: MovieAdapter? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.hello_activity) + val rvMovieList: RecyclerView = findViewById(R.id.hello_activity__rv_movie_list) + adapter = MovieAdapter(movies) + rvMovieList.adapter = adapter + rvMovieList.layoutManager = LinearLayoutManager(this) + val button: FloatingActionButton = findViewById(R.id.hello_activity__fab_add_movie) + button.setOnClickListener { onClick() } + } + + private fun onClick() { + movies.add( + Movie( + "Мой новый фильм", + "Здесь описание фильма", + 0 + ) + ) + adapter?.notifyDataSetChanged() + } +} + +private fun generateMovieList(): List { + return listOf( + Movie( + "Побег из Шоушенка", + "Оказавшись в тюрьме под названием Шоушенк, он сталкивается с жестокостью и беззаконием, царящими по обе стороны решетки. Каждый, кто попадает в эти стены, становится их рабом до конца жизни", + R.drawable.movie_1 + ), Movie( + "Матрица", + "Жизнь Томаса Андерсона разделена на две части: днём он — самый обычный офисный работник, получающий нагоняи от начальства, а ночью превращается в хакера по имени Нео, и нет места в сети, куда он не смог бы дотянуться", + R.drawable.movie_2 + ), Movie( + "Как приручить дракона", + "Вы узнаете историю подростка Иккинга, которому не слишком близки традиции его героического племени, много лет ведущего войну с драконами", + R.drawable.movie_3 + ), Movie( + "12 стульев", + "Во время революции и последовавшего за ней краткого периода военного коммунизма многие прятали свои ценности как можно надежнее", + R.drawable.movie_4 + ), Movie( + "Зеленая книга", + "Утонченный светский лев, богатый и талантливый музыкант нанимает в качестве водителя и телохранителя человека, который менее всего подходит для этой работы", + R.drawable.movie_5 + ), Movie( + "Пираты Карибского моря: Проклятие Черной жемчужины", + "Жизнь харизматичного авантюриста, капитана Джека Воробья, полная увлекательных приключений, резко меняется, когда его заклятый враг — капитан Барбосса — похищает корабль Джека, Черную Жемчужину, а затем нападает на Порт Ройал и крадет прекрасную дочь губернатора, Элизабет Свонн.", + R.drawable.movie_6 + ), Movie( + "Гарри Поттер и философский камень", + "Жизнь десятилетнего Гарри Поттера нельзя назвать сладкой: его родители умерли, едва ему исполнился год, а от дяди и тётки, взявших сироту на воспитание, достаются лишь тычки да подзатыльники", + R.drawable.movie_7 + ) + ) +} \ No newline at end of file diff --git a/lection02/app/src/main/java/com/mycompany/helloworld/Movie.kt b/lection02/app/src/main/java/com/mycompany/helloworld/Movie.kt new file mode 100644 index 0000000..86932b5 --- /dev/null +++ b/lection02/app/src/main/java/com/mycompany/helloworld/Movie.kt @@ -0,0 +1,3 @@ +package com.mycompany.helloworld + +data class Movie(val title: String, val description: String, val picture: Int) \ No newline at end of file diff --git a/lection02/app/src/main/java/com/mycompany/helloworld/MovieAdapter.kt b/lection02/app/src/main/java/com/mycompany/helloworld/MovieAdapter.kt new file mode 100644 index 0000000..94d57a0 --- /dev/null +++ b/lection02/app/src/main/java/com/mycompany/helloworld/MovieAdapter.kt @@ -0,0 +1,54 @@ +package com.mycompany.helloworld + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import android.widget.Toast +import androidx.recyclerview.widget.RecyclerView + +class MovieAdapter(private val movies: List) : + RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder { + val view = LayoutInflater.from(parent.context).inflate(R.layout.movie_item, parent, false) + return MovieViewHolder(view) + } + + override fun onBindViewHolder(holder: MovieViewHolder, position: Int) { + val movie = movies[position] + holder.bind(movie) + } + + override fun getItemCount(): Int { + println("Movies size = ${movies.size}") + return movies.size + } + + class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + + private val tvName: TextView = itemView.findViewById(R.id.movie_item__tv_name) + private val tvDescription: TextView = itemView.findViewById(R.id.movie_item__tv_description) + private val ivPoster: ImageView = itemView.findViewById(R.id.movie_item__iv_poster) + + init { + itemView.setOnClickListener { + Toast.makeText( + itemView.context, + tvName.text, + Toast.LENGTH_SHORT + ).show() + } + } + + fun bind(movie: Movie) { + tvName.text = movie.title + tvDescription.text = movie.description + ivPoster.setImageResource(movie.picture) + } + + } + + +} \ No newline at end of file diff --git a/lection02/app/src/main/res/drawable-hdpi/movie_1.png b/lection02/app/src/main/res/drawable-hdpi/movie_1.png new file mode 100755 index 0000000..106a031 Binary files /dev/null and b/lection02/app/src/main/res/drawable-hdpi/movie_1.png differ diff --git a/lection02/app/src/main/res/drawable-hdpi/movie_2.png b/lection02/app/src/main/res/drawable-hdpi/movie_2.png new file mode 100755 index 0000000..b93365e Binary files /dev/null and b/lection02/app/src/main/res/drawable-hdpi/movie_2.png differ diff --git a/lection02/app/src/main/res/drawable-hdpi/movie_3.png b/lection02/app/src/main/res/drawable-hdpi/movie_3.png new file mode 100755 index 0000000..aa9bf6a Binary files /dev/null and b/lection02/app/src/main/res/drawable-hdpi/movie_3.png differ diff --git a/lection02/app/src/main/res/drawable-hdpi/movie_4.png b/lection02/app/src/main/res/drawable-hdpi/movie_4.png new file mode 100755 index 0000000..afcff88 Binary files /dev/null and b/lection02/app/src/main/res/drawable-hdpi/movie_4.png differ diff --git a/lection02/app/src/main/res/drawable-hdpi/movie_5.png b/lection02/app/src/main/res/drawable-hdpi/movie_5.png new file mode 100755 index 0000000..7541f5c Binary files /dev/null and b/lection02/app/src/main/res/drawable-hdpi/movie_5.png differ diff --git a/lection02/app/src/main/res/drawable-hdpi/movie_6.png b/lection02/app/src/main/res/drawable-hdpi/movie_6.png new file mode 100755 index 0000000..12c3452 Binary files /dev/null and b/lection02/app/src/main/res/drawable-hdpi/movie_6.png differ diff --git a/lection02/app/src/main/res/drawable-hdpi/movie_7.png b/lection02/app/src/main/res/drawable-hdpi/movie_7.png new file mode 100755 index 0000000..94171cf Binary files /dev/null and b/lection02/app/src/main/res/drawable-hdpi/movie_7.png differ diff --git a/lection02/app/src/main/res/drawable-ldpi/movie_1.png b/lection02/app/src/main/res/drawable-ldpi/movie_1.png new file mode 100755 index 0000000..dae8e7e Binary files /dev/null and b/lection02/app/src/main/res/drawable-ldpi/movie_1.png differ diff --git a/lection02/app/src/main/res/drawable-ldpi/movie_2.png b/lection02/app/src/main/res/drawable-ldpi/movie_2.png new file mode 100755 index 0000000..87fe93b Binary files /dev/null and b/lection02/app/src/main/res/drawable-ldpi/movie_2.png differ diff --git a/lection02/app/src/main/res/drawable-ldpi/movie_3.png b/lection02/app/src/main/res/drawable-ldpi/movie_3.png new file mode 100755 index 0000000..d9afa44 Binary files /dev/null and b/lection02/app/src/main/res/drawable-ldpi/movie_3.png differ diff --git a/lection02/app/src/main/res/drawable-ldpi/movie_4.png b/lection02/app/src/main/res/drawable-ldpi/movie_4.png new file mode 100755 index 0000000..af94f73 Binary files /dev/null and b/lection02/app/src/main/res/drawable-ldpi/movie_4.png differ diff --git a/lection02/app/src/main/res/drawable-ldpi/movie_5.png b/lection02/app/src/main/res/drawable-ldpi/movie_5.png new file mode 100755 index 0000000..90cef94 Binary files /dev/null and b/lection02/app/src/main/res/drawable-ldpi/movie_5.png differ diff --git a/lection02/app/src/main/res/drawable-ldpi/movie_6.png b/lection02/app/src/main/res/drawable-ldpi/movie_6.png new file mode 100755 index 0000000..62da4ea Binary files /dev/null and b/lection02/app/src/main/res/drawable-ldpi/movie_6.png differ diff --git a/lection02/app/src/main/res/drawable-ldpi/movie_7.png b/lection02/app/src/main/res/drawable-ldpi/movie_7.png new file mode 100755 index 0000000..8e601d9 Binary files /dev/null and b/lection02/app/src/main/res/drawable-ldpi/movie_7.png differ diff --git a/lection02/app/src/main/res/drawable-mdpi/movie_1.png b/lection02/app/src/main/res/drawable-mdpi/movie_1.png new file mode 100755 index 0000000..9763aeb Binary files /dev/null and b/lection02/app/src/main/res/drawable-mdpi/movie_1.png differ diff --git a/lection02/app/src/main/res/drawable-mdpi/movie_2.png b/lection02/app/src/main/res/drawable-mdpi/movie_2.png new file mode 100755 index 0000000..e72b6dc Binary files /dev/null and b/lection02/app/src/main/res/drawable-mdpi/movie_2.png differ diff --git a/lection02/app/src/main/res/drawable-mdpi/movie_3.png b/lection02/app/src/main/res/drawable-mdpi/movie_3.png new file mode 100755 index 0000000..2f15fb9 Binary files /dev/null and b/lection02/app/src/main/res/drawable-mdpi/movie_3.png differ diff --git a/lection02/app/src/main/res/drawable-mdpi/movie_4.png b/lection02/app/src/main/res/drawable-mdpi/movie_4.png new file mode 100755 index 0000000..7a8cd92 Binary files /dev/null and b/lection02/app/src/main/res/drawable-mdpi/movie_4.png differ diff --git a/lection02/app/src/main/res/drawable-mdpi/movie_5.png b/lection02/app/src/main/res/drawable-mdpi/movie_5.png new file mode 100755 index 0000000..4a0bfae Binary files /dev/null and b/lection02/app/src/main/res/drawable-mdpi/movie_5.png differ diff --git a/lection02/app/src/main/res/drawable-mdpi/movie_6.png b/lection02/app/src/main/res/drawable-mdpi/movie_6.png new file mode 100755 index 0000000..d23a801 Binary files /dev/null and b/lection02/app/src/main/res/drawable-mdpi/movie_6.png differ diff --git a/lection02/app/src/main/res/drawable-mdpi/movie_7.png b/lection02/app/src/main/res/drawable-mdpi/movie_7.png new file mode 100755 index 0000000..830afeb Binary files /dev/null and b/lection02/app/src/main/res/drawable-mdpi/movie_7.png differ diff --git a/lection02/app/src/main/res/drawable-xhdpi/movie_1.png b/lection02/app/src/main/res/drawable-xhdpi/movie_1.png new file mode 100755 index 0000000..59afb66 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xhdpi/movie_1.png differ diff --git a/lection02/app/src/main/res/drawable-xhdpi/movie_2.png b/lection02/app/src/main/res/drawable-xhdpi/movie_2.png new file mode 100755 index 0000000..89088d5 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xhdpi/movie_2.png differ diff --git a/lection02/app/src/main/res/drawable-xhdpi/movie_3.png b/lection02/app/src/main/res/drawable-xhdpi/movie_3.png new file mode 100755 index 0000000..97aca7d Binary files /dev/null and b/lection02/app/src/main/res/drawable-xhdpi/movie_3.png differ diff --git a/lection02/app/src/main/res/drawable-xhdpi/movie_4.png b/lection02/app/src/main/res/drawable-xhdpi/movie_4.png new file mode 100755 index 0000000..d85fcd7 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xhdpi/movie_4.png differ diff --git a/lection02/app/src/main/res/drawable-xhdpi/movie_5.png b/lection02/app/src/main/res/drawable-xhdpi/movie_5.png new file mode 100755 index 0000000..27c9de2 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xhdpi/movie_5.png differ diff --git a/lection02/app/src/main/res/drawable-xhdpi/movie_6.png b/lection02/app/src/main/res/drawable-xhdpi/movie_6.png new file mode 100755 index 0000000..fd9c277 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xhdpi/movie_6.png differ diff --git a/lection02/app/src/main/res/drawable-xhdpi/movie_7.png b/lection02/app/src/main/res/drawable-xhdpi/movie_7.png new file mode 100755 index 0000000..88cc321 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xhdpi/movie_7.png differ diff --git a/lection02/app/src/main/res/drawable-xxhdpi/movie_1.png b/lection02/app/src/main/res/drawable-xxhdpi/movie_1.png new file mode 100755 index 0000000..47f758d Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxhdpi/movie_1.png differ diff --git a/lection02/app/src/main/res/drawable-xxhdpi/movie_2.png b/lection02/app/src/main/res/drawable-xxhdpi/movie_2.png new file mode 100755 index 0000000..0188d5e Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxhdpi/movie_2.png differ diff --git a/lection02/app/src/main/res/drawable-xxhdpi/movie_3.png b/lection02/app/src/main/res/drawable-xxhdpi/movie_3.png new file mode 100755 index 0000000..1c94edf Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxhdpi/movie_3.png differ diff --git a/lection02/app/src/main/res/drawable-xxhdpi/movie_4.png b/lection02/app/src/main/res/drawable-xxhdpi/movie_4.png new file mode 100755 index 0000000..cfbe346 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxhdpi/movie_4.png differ diff --git a/lection02/app/src/main/res/drawable-xxhdpi/movie_5.png b/lection02/app/src/main/res/drawable-xxhdpi/movie_5.png new file mode 100755 index 0000000..4bb4915 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxhdpi/movie_5.png differ diff --git a/lection02/app/src/main/res/drawable-xxhdpi/movie_6.png b/lection02/app/src/main/res/drawable-xxhdpi/movie_6.png new file mode 100755 index 0000000..8ed7d30 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxhdpi/movie_6.png differ diff --git a/lection02/app/src/main/res/drawable-xxhdpi/movie_7.png b/lection02/app/src/main/res/drawable-xxhdpi/movie_7.png new file mode 100755 index 0000000..43bf92c Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxhdpi/movie_7.png differ diff --git a/lection02/app/src/main/res/drawable-xxxhdpi/movie_1.png b/lection02/app/src/main/res/drawable-xxxhdpi/movie_1.png new file mode 100755 index 0000000..5b46e33 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxxhdpi/movie_1.png differ diff --git a/lection02/app/src/main/res/drawable-xxxhdpi/movie_2.png b/lection02/app/src/main/res/drawable-xxxhdpi/movie_2.png new file mode 100755 index 0000000..c103544 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxxhdpi/movie_2.png differ diff --git a/lection02/app/src/main/res/drawable-xxxhdpi/movie_3.png b/lection02/app/src/main/res/drawable-xxxhdpi/movie_3.png new file mode 100755 index 0000000..b7cbf3f Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxxhdpi/movie_3.png differ diff --git a/lection02/app/src/main/res/drawable-xxxhdpi/movie_4.png b/lection02/app/src/main/res/drawable-xxxhdpi/movie_4.png new file mode 100755 index 0000000..eb94bd4 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxxhdpi/movie_4.png differ diff --git a/lection02/app/src/main/res/drawable-xxxhdpi/movie_5.png b/lection02/app/src/main/res/drawable-xxxhdpi/movie_5.png new file mode 100755 index 0000000..52ed058 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxxhdpi/movie_5.png differ diff --git a/lection02/app/src/main/res/drawable-xxxhdpi/movie_6.png b/lection02/app/src/main/res/drawable-xxxhdpi/movie_6.png new file mode 100755 index 0000000..be3124f Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxxhdpi/movie_6.png differ diff --git a/lection02/app/src/main/res/drawable-xxxhdpi/movie_7.png b/lection02/app/src/main/res/drawable-xxxhdpi/movie_7.png new file mode 100755 index 0000000..e54b995 Binary files /dev/null and b/lection02/app/src/main/res/drawable-xxxhdpi/movie_7.png differ diff --git a/lection02/app/src/main/res/layout/hello_activity.xml b/lection02/app/src/main/res/layout/hello_activity.xml new file mode 100644 index 0000000..530dd75 --- /dev/null +++ b/lection02/app/src/main/res/layout/hello_activity.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/lection02/app/src/main/res/layout/movie_item.xml b/lection02/app/src/main/res/layout/movie_item.xml new file mode 100644 index 0000000..87d8c96 --- /dev/null +++ b/lection02/app/src/main/res/layout/movie_item.xml @@ -0,0 +1,51 @@ + + + + + + + + + + \ No newline at end of file diff --git a/lection02/app/src/main/res/mipmap-hdpi/ic_launcher.png b/lection02/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..9942626 Binary files /dev/null and b/lection02/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/lection02/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/lection02/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..61da551 Binary files /dev/null and b/lection02/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/lection02/app/src/main/res/mipmap-mdpi/ic_launcher.png b/lection02/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c41dd28 Binary files /dev/null and b/lection02/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/lection02/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/lection02/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db5080a Binary files /dev/null and b/lection02/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/lection02/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/lection02/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..8fa9fcd Binary files /dev/null and b/lection02/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/lection02/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/lection02/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..da31a87 Binary files /dev/null and b/lection02/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/lection02/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/lection02/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..f966b99 Binary files /dev/null and b/lection02/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/lection02/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/lection02/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b216f2d Binary files /dev/null and b/lection02/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/lection02/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection02/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..04627d1 Binary files /dev/null and b/lection02/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/lection02/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/lection02/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e96783c Binary files /dev/null and b/lection02/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/lection02/build.gradle b/lection02/build.gradle deleted file mode 100644 index 611ef82..0000000 --- a/lection02/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath "com.android.tools.build:gradle:7.0.2" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} \ No newline at end of file diff --git a/lection02/gradle/wrapper/gradle-wrapper.jar b/lection02/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c..0000000 Binary files a/lection02/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/lection02/settings.gradle b/lection02/settings.gradle deleted file mode 100644 index 295c08f..0000000 --- a/lection02/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) - repositories { - google() - mavenCentral() - jcenter() // Warning: this repository is going to shut down soon - } -} -rootProject.name = "Lesson02" -include ':app' diff --git a/lection03/.gitignore b/lection03/.gitignore deleted file mode 100644 index 0b7b04c..0000000 --- a/lection03/.gitignore +++ /dev/null @@ -1,89 +0,0 @@ -# Built application files -*.apk -*.aar -*.ap_ -*.aab - -# Files for the ART/Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -bin/ -gen/ -out/ -# Uncomment the following line in case you need and you don't have the release build type files in your app -# release/ - -# Gradle files -.gradle/ -build/ - -# Local configuration file (sdk path, etc) -local.properties - -# Proguard folder generated by Eclipse -proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -.navigation/ - -# Android Studio captures folder -captures/ - -# IntelliJ -*.iml -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/assetWizardSettings.xml -.idea/dictionaries -.idea/libraries -.idea/jarRepositories.xml -# Android Studio 3 in .gitignore file. -.idea/caches -.idea/modules.xml -# Comment next line if keeping position of elements in Navigation Editor is relevant for you -.idea/navEditor.xml - -# Keystore files -# Uncomment the following lines if you do not want to check your keystore files in. -#*.jks -#*.keystore - -# External native build folder generated in Android Studio 2.2 and later -.externalNativeBuild -.cxx/ - -# Google Services (e.g. APIs or Firebase) -# google-services.json - -# Freeline -freeline.py -freeline/ -freeline_project_description.json - -# fastlane -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output -fastlane/readme.md - -# Version control -vcs.xml - -# lint -lint/intermediates/ -lint/generated/ -lint/outputs/ -lint/tmp/ -# lint/reports/ - -# Android Profiling -*.hprof \ No newline at end of file diff --git a/lection03/.idea/.gitignore b/lection03/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/lection03/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/lection03/.idea/.name b/lection03/.idea/.name deleted file mode 100644 index 2b7e585..0000000 --- a/lection03/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -hello_world \ No newline at end of file diff --git a/lection05/.idea/gradle.xml b/lection03/.idea/gradle.xml similarity index 80% rename from lection05/.idea/gradle.xml rename to lection03/.idea/gradle.xml index e9969a1..23a89bb 100644 --- a/lection05/.idea/gradle.xml +++ b/lection03/.idea/gradle.xml @@ -4,10 +4,10 @@ diff --git a/lection03/.idea/jarRepositories.xml b/lection03/.idea/jarRepositories.xml new file mode 100644 index 0000000..a5f05cd --- /dev/null +++ b/lection03/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lection03/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt b/lection03/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..e9283cf --- /dev/null +++ b/lection03/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.myapplication + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.myapplication", appContext.packageName) + } +} \ No newline at end of file diff --git a/lection03/app/src/main/java/com/example/myapplication/AbstractActivity.kt b/lection03/app/src/main/java/com/example/myapplication/AbstractActivity.kt new file mode 100644 index 0000000..6307d35 --- /dev/null +++ b/lection03/app/src/main/java/com/example/myapplication/AbstractActivity.kt @@ -0,0 +1,49 @@ +package com.example.myapplication + +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import android.util.Log +import androidx.appcompat.app.AppCompatActivity + +abstract class AbstractActivity: AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + Log.d(TAG, "onCreate") + } + + override fun onPause() { + super.onPause() + + Log.d(TAG, "onPause") + } + + override fun onStop() { + super.onStop() + + Log.d(TAG, "onStop") + + + if (isFinishing) { + Log.d(TAG, "onStop - isFinishing:$isFinishing") + } + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + + Log.d(TAG, "onConfigurationChanged") + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + + Log.d(TAG, "onNewIntent") + } + + + companion object { + const val TAG = "AbstractActivity" + } +} \ No newline at end of file diff --git a/lection03/app/src/main/java/com/example/myapplication/DataFragment.kt b/lection03/app/src/main/java/com/example/myapplication/DataFragment.kt new file mode 100644 index 0000000..f304ea4 --- /dev/null +++ b/lection03/app/src/main/java/com/example/myapplication/DataFragment.kt @@ -0,0 +1,81 @@ +package com.example.myapplication + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment + +class DataFragment: Fragment() { + var navigator: INavigation? = null + + var textView: TextView? = null + var cachedView: View? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + +// parentFragment + navigator = (requireActivity() as? INavigation) + } + + override fun onDetach() { + super.onDetach() + + navigator = null + } + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // грязный хак +// if (cachedView == null) { +// cachedView = inflater.inflate(R.layout.activity_main, container, false) +// } +// +// return cachedView + + return inflater.inflate(R.layout.activity_main, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + textView = view.findViewById(R.id.dummy) + + textView?.apply { + text = arguments!!.getString("timestamp") + } + } + + override fun onDestroyView() { + super.onDestroyView() + + textView = null + } + + + fun updateData(data: String) { + textView?.apply { + text = data + } + } + + + companion object { + fun create(timestamp: String): DataFragment { + val extras = Bundle().apply { + putString("timestamp", timestamp) + } + + return DataFragment().apply { + arguments = extras + } + } + } +} \ No newline at end of file diff --git a/lection03/app/src/main/java/com/example/myapplication/DroidParcel.kt b/lection03/app/src/main/java/com/example/myapplication/DroidParcel.kt new file mode 100644 index 0000000..66abe10 --- /dev/null +++ b/lection03/app/src/main/java/com/example/myapplication/DroidParcel.kt @@ -0,0 +1,33 @@ +package com.example.myapplication + +import android.os.Parcel +import android.os.Parcelable + +class DroidParcel(): Parcelable { + var id: Int = 0 + var name: String = "0" + + constructor(parcel: Parcel) : this() { + id = parcel.readInt() + name = parcel.readString()!! + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(id) + parcel.writeString(name) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): DroidParcel { + return DroidParcel(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/lection03/app/src/main/java/com/example/myapplication/INavigation.kt b/lection03/app/src/main/java/com/example/myapplication/INavigation.kt new file mode 100644 index 0000000..c4f7951 --- /dev/null +++ b/lection03/app/src/main/java/com/example/myapplication/INavigation.kt @@ -0,0 +1,5 @@ +package com.example.myapplication + +interface INavigation { + fun showData(data: String) +} \ No newline at end of file diff --git a/lection03/app/src/main/java/com/example/myapplication/ListFragment.kt b/lection03/app/src/main/java/com/example/myapplication/ListFragment.kt new file mode 100644 index 0000000..07c8739 --- /dev/null +++ b/lection03/app/src/main/java/com/example/myapplication/ListFragment.kt @@ -0,0 +1,43 @@ +package com.example.myapplication + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment + +class ListFragment: Fragment() { + var navigator: INavigation? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + +// parentFragment + navigator = (requireActivity() as? INavigation) + } + + override fun onDetach() { + super.onDetach() + + navigator = null + } + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.activity_main, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + view.findViewById(R.id.dummy).setOnClickListener { + navigator?.showData(System.currentTimeMillis().toString()) + } + } +} \ No newline at end of file diff --git a/lection03/app/src/main/java/com/example/myapplication/MainActivity.kt b/lection03/app/src/main/java/com/example/myapplication/MainActivity.kt new file mode 100644 index 0000000..2e41953 --- /dev/null +++ b/lection03/app/src/main/java/com/example/myapplication/MainActivity.kt @@ -0,0 +1,41 @@ +package com.example.myapplication + +import android.os.Bundle + +class MainActivity : AbstractActivity(), INavigation { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_two_panel) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) + + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + + + } + + override fun showData(data: String) { + val fragment = DataFragment.create(data) + + val dataFragment = supportFragmentManager.findFragmentByTag("DATA") as? DataFragment + + when (dataFragment) { + null -> { + supportFragmentManager + .beginTransaction() + .replace(R.id.container, fragment, "DATA") + .addToBackStack(null) + .commit() + } + + else -> { + dataFragment.updateData(data) + } + } + } +} \ No newline at end of file diff --git a/lection03/app/src/main/java/com/mmmm/DummyActivity.kt b/lection03/app/src/main/java/com/mmmm/DummyActivity.kt new file mode 100644 index 0000000..8ba6fe1 --- /dev/null +++ b/lection03/app/src/main/java/com/mmmm/DummyActivity.kt @@ -0,0 +1,40 @@ +package com.mmmm + +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import android.view.View +import android.widget.TextView +import androidx.core.net.toUri +import com.example.myapplication.AbstractActivity +import com.example.myapplication.DroidParcel +import com.example.myapplication.MainActivity + +class DummyActivity: AbstractActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val deeplink = intent.data!! + val droid = intent.getParcelableExtra("droid")!! + + + val view = TextView(this).apply { + setBackgroundColor(Color.WHITE) + setTextColor(Color.BLACK) + text = droid.name + + setOnClickListener { + val intent = Intent(applicationContext, MainActivity::class.java) + startActivity(intent) + } + } + setContentView(view) + + val result = Intent().apply { + data = "droid://${droid.name}/${droid.id}".toUri() + } + + setResult(RESULT_OK, result) + finish() + } +} \ No newline at end of file diff --git a/lection03/app/src/main/res/drawable-hdpi/movie_1.png b/lection03/app/src/main/res/drawable-hdpi/movie_1.png old mode 100755 new mode 100644 index 106a031..39aa2b7 Binary files a/lection03/app/src/main/res/drawable-hdpi/movie_1.png and b/lection03/app/src/main/res/drawable-hdpi/movie_1.png differ diff --git a/lection03/app/src/main/res/drawable-hdpi/movie_3.png b/lection03/app/src/main/res/drawable-hdpi/movie_3.png old mode 100755 new mode 100644 index aa9bf6a..cc4f1a9 Binary files a/lection03/app/src/main/res/drawable-hdpi/movie_3.png and b/lection03/app/src/main/res/drawable-hdpi/movie_3.png differ diff --git a/lection03/app/src/main/res/drawable-hdpi/movie_4.png b/lection03/app/src/main/res/drawable-hdpi/movie_4.png old mode 100755 new mode 100644 index afcff88..8fbc644 Binary files a/lection03/app/src/main/res/drawable-hdpi/movie_4.png and b/lection03/app/src/main/res/drawable-hdpi/movie_4.png differ diff --git a/lection03/app/src/main/res/drawable-hdpi/movie_5.png b/lection03/app/src/main/res/drawable-hdpi/movie_5.png old mode 100755 new mode 100644 index 7541f5c..23573cd Binary files a/lection03/app/src/main/res/drawable-hdpi/movie_5.png and b/lection03/app/src/main/res/drawable-hdpi/movie_5.png differ diff --git a/lection03/app/src/main/res/drawable-hdpi/movie_6.png b/lection03/app/src/main/res/drawable-hdpi/movie_6.png old mode 100755 new mode 100644 index 12c3452..0eea8b4 Binary files a/lection03/app/src/main/res/drawable-hdpi/movie_6.png and b/lection03/app/src/main/res/drawable-hdpi/movie_6.png differ diff --git a/lection03/app/src/main/res/drawable-hdpi/movie_7.png b/lection03/app/src/main/res/drawable-hdpi/movie_7.png old mode 100755 new mode 100644 index 94171cf..18eecf0 Binary files a/lection03/app/src/main/res/drawable-hdpi/movie_7.png and b/lection03/app/src/main/res/drawable-hdpi/movie_7.png differ diff --git a/lection03/app/src/main/res/drawable-ldpi/movie_1.png b/lection03/app/src/main/res/drawable-ldpi/movie_1.png old mode 100755 new mode 100644 index dae8e7e..866e349 Binary files a/lection03/app/src/main/res/drawable-ldpi/movie_1.png and b/lection03/app/src/main/res/drawable-ldpi/movie_1.png differ diff --git a/lection03/app/src/main/res/drawable-ldpi/movie_3.png b/lection03/app/src/main/res/drawable-ldpi/movie_3.png old mode 100755 new mode 100644 index d9afa44..7cdd8be Binary files a/lection03/app/src/main/res/drawable-ldpi/movie_3.png and b/lection03/app/src/main/res/drawable-ldpi/movie_3.png differ diff --git a/lection03/app/src/main/res/drawable-ldpi/movie_4.png b/lection03/app/src/main/res/drawable-ldpi/movie_4.png old mode 100755 new mode 100644 index af94f73..4025078 Binary files a/lection03/app/src/main/res/drawable-ldpi/movie_4.png and b/lection03/app/src/main/res/drawable-ldpi/movie_4.png differ diff --git a/lection03/app/src/main/res/drawable-ldpi/movie_5.png b/lection03/app/src/main/res/drawable-ldpi/movie_5.png old mode 100755 new mode 100644 index 90cef94..cf8d264 Binary files a/lection03/app/src/main/res/drawable-ldpi/movie_5.png and b/lection03/app/src/main/res/drawable-ldpi/movie_5.png differ diff --git a/lection03/app/src/main/res/drawable-ldpi/movie_6.png b/lection03/app/src/main/res/drawable-ldpi/movie_6.png old mode 100755 new mode 100644 index 62da4ea..b475f8f Binary files a/lection03/app/src/main/res/drawable-ldpi/movie_6.png and b/lection03/app/src/main/res/drawable-ldpi/movie_6.png differ diff --git a/lection03/app/src/main/res/drawable-ldpi/movie_7.png b/lection03/app/src/main/res/drawable-ldpi/movie_7.png old mode 100755 new mode 100644 index 8e601d9..74f1c89 Binary files a/lection03/app/src/main/res/drawable-ldpi/movie_7.png and b/lection03/app/src/main/res/drawable-ldpi/movie_7.png differ diff --git a/lection03/app/src/main/res/drawable-mdpi/movie_1.png b/lection03/app/src/main/res/drawable-mdpi/movie_1.png old mode 100755 new mode 100644 index 9763aeb..6316007 Binary files a/lection03/app/src/main/res/drawable-mdpi/movie_1.png and b/lection03/app/src/main/res/drawable-mdpi/movie_1.png differ diff --git a/lection03/app/src/main/res/drawable-mdpi/movie_3.png b/lection03/app/src/main/res/drawable-mdpi/movie_3.png old mode 100755 new mode 100644 index 2f15fb9..dc68342 Binary files a/lection03/app/src/main/res/drawable-mdpi/movie_3.png and b/lection03/app/src/main/res/drawable-mdpi/movie_3.png differ diff --git a/lection03/app/src/main/res/drawable-mdpi/movie_4.png b/lection03/app/src/main/res/drawable-mdpi/movie_4.png old mode 100755 new mode 100644 index 7a8cd92..64a27e2 Binary files a/lection03/app/src/main/res/drawable-mdpi/movie_4.png and b/lection03/app/src/main/res/drawable-mdpi/movie_4.png differ diff --git a/lection03/app/src/main/res/drawable-mdpi/movie_5.png b/lection03/app/src/main/res/drawable-mdpi/movie_5.png old mode 100755 new mode 100644 index 4a0bfae..dcc0794 Binary files a/lection03/app/src/main/res/drawable-mdpi/movie_5.png and b/lection03/app/src/main/res/drawable-mdpi/movie_5.png differ diff --git a/lection03/app/src/main/res/drawable-mdpi/movie_6.png b/lection03/app/src/main/res/drawable-mdpi/movie_6.png old mode 100755 new mode 100644 index d23a801..70a48c2 Binary files a/lection03/app/src/main/res/drawable-mdpi/movie_6.png and b/lection03/app/src/main/res/drawable-mdpi/movie_6.png differ diff --git a/lection03/app/src/main/res/drawable-mdpi/movie_7.png b/lection03/app/src/main/res/drawable-mdpi/movie_7.png old mode 100755 new mode 100644 index 830afeb..0b3c103 Binary files a/lection03/app/src/main/res/drawable-mdpi/movie_7.png and b/lection03/app/src/main/res/drawable-mdpi/movie_7.png differ diff --git a/lection03/app/src/main/res/drawable-xhdpi/movie_1.png b/lection03/app/src/main/res/drawable-xhdpi/movie_1.png old mode 100755 new mode 100644 index 59afb66..f7e06eb Binary files a/lection03/app/src/main/res/drawable-xhdpi/movie_1.png and b/lection03/app/src/main/res/drawable-xhdpi/movie_1.png differ diff --git a/lection03/app/src/main/res/drawable-xhdpi/movie_2.png b/lection03/app/src/main/res/drawable-xhdpi/movie_2.png old mode 100755 new mode 100644 index 89088d5..bf6c2c6 Binary files a/lection03/app/src/main/res/drawable-xhdpi/movie_2.png and b/lection03/app/src/main/res/drawable-xhdpi/movie_2.png differ diff --git a/lection03/app/src/main/res/drawable-xhdpi/movie_3.png b/lection03/app/src/main/res/drawable-xhdpi/movie_3.png old mode 100755 new mode 100644 index 97aca7d..2348861 Binary files a/lection03/app/src/main/res/drawable-xhdpi/movie_3.png and b/lection03/app/src/main/res/drawable-xhdpi/movie_3.png differ diff --git a/lection03/app/src/main/res/drawable-xhdpi/movie_4.png b/lection03/app/src/main/res/drawable-xhdpi/movie_4.png old mode 100755 new mode 100644 index d85fcd7..a917f0f Binary files a/lection03/app/src/main/res/drawable-xhdpi/movie_4.png and b/lection03/app/src/main/res/drawable-xhdpi/movie_4.png differ diff --git a/lection03/app/src/main/res/drawable-xhdpi/movie_5.png b/lection03/app/src/main/res/drawable-xhdpi/movie_5.png old mode 100755 new mode 100644 index 27c9de2..3ae09a3 Binary files a/lection03/app/src/main/res/drawable-xhdpi/movie_5.png and b/lection03/app/src/main/res/drawable-xhdpi/movie_5.png differ diff --git a/lection03/app/src/main/res/drawable-xhdpi/movie_6.png b/lection03/app/src/main/res/drawable-xhdpi/movie_6.png old mode 100755 new mode 100644 index fd9c277..0a94f9e Binary files a/lection03/app/src/main/res/drawable-xhdpi/movie_6.png and b/lection03/app/src/main/res/drawable-xhdpi/movie_6.png differ diff --git a/lection03/app/src/main/res/drawable-xhdpi/movie_7.png b/lection03/app/src/main/res/drawable-xhdpi/movie_7.png old mode 100755 new mode 100644 index 88cc321..6510db8 Binary files a/lection03/app/src/main/res/drawable-xhdpi/movie_7.png and b/lection03/app/src/main/res/drawable-xhdpi/movie_7.png differ diff --git a/lection03/app/src/main/res/drawable-xxhdpi/movie_1.png b/lection03/app/src/main/res/drawable-xxhdpi/movie_1.png old mode 100755 new mode 100644 index 47f758d..f51499d Binary files a/lection03/app/src/main/res/drawable-xxhdpi/movie_1.png and b/lection03/app/src/main/res/drawable-xxhdpi/movie_1.png differ diff --git a/lection03/app/src/main/res/drawable-xxhdpi/movie_3.png b/lection03/app/src/main/res/drawable-xxhdpi/movie_3.png old mode 100755 new mode 100644 index 1c94edf..fffb7fe Binary files a/lection03/app/src/main/res/drawable-xxhdpi/movie_3.png and b/lection03/app/src/main/res/drawable-xxhdpi/movie_3.png differ diff --git a/lection03/app/src/main/res/drawable-xxhdpi/movie_4.png b/lection03/app/src/main/res/drawable-xxhdpi/movie_4.png old mode 100755 new mode 100644 index cfbe346..297de6d Binary files a/lection03/app/src/main/res/drawable-xxhdpi/movie_4.png and b/lection03/app/src/main/res/drawable-xxhdpi/movie_4.png differ diff --git a/lection03/app/src/main/res/drawable-xxhdpi/movie_5.png b/lection03/app/src/main/res/drawable-xxhdpi/movie_5.png old mode 100755 new mode 100644 index 4bb4915..9e42076 Binary files a/lection03/app/src/main/res/drawable-xxhdpi/movie_5.png and b/lection03/app/src/main/res/drawable-xxhdpi/movie_5.png differ diff --git a/lection03/app/src/main/res/drawable-xxhdpi/movie_6.png b/lection03/app/src/main/res/drawable-xxhdpi/movie_6.png old mode 100755 new mode 100644 index 8ed7d30..477ef1d Binary files a/lection03/app/src/main/res/drawable-xxhdpi/movie_6.png and b/lection03/app/src/main/res/drawable-xxhdpi/movie_6.png differ diff --git a/lection03/app/src/main/res/drawable-xxhdpi/movie_7.png b/lection03/app/src/main/res/drawable-xxhdpi/movie_7.png old mode 100755 new mode 100644 index 43bf92c..b459026 Binary files a/lection03/app/src/main/res/drawable-xxhdpi/movie_7.png and b/lection03/app/src/main/res/drawable-xxhdpi/movie_7.png differ diff --git a/lection03/app/src/main/res/drawable-xxxhdpi/movie_1.png b/lection03/app/src/main/res/drawable-xxxhdpi/movie_1.png old mode 100755 new mode 100644 index 5b46e33..027e036 Binary files a/lection03/app/src/main/res/drawable-xxxhdpi/movie_1.png and b/lection03/app/src/main/res/drawable-xxxhdpi/movie_1.png differ diff --git a/lection03/app/src/main/res/drawable-xxxhdpi/movie_3.png b/lection03/app/src/main/res/drawable-xxxhdpi/movie_3.png old mode 100755 new mode 100644 index b7cbf3f..6644788 Binary files a/lection03/app/src/main/res/drawable-xxxhdpi/movie_3.png and b/lection03/app/src/main/res/drawable-xxxhdpi/movie_3.png differ diff --git a/lection03/app/src/main/res/drawable-xxxhdpi/movie_4.png b/lection03/app/src/main/res/drawable-xxxhdpi/movie_4.png old mode 100755 new mode 100644 index eb94bd4..ec60a42 Binary files a/lection03/app/src/main/res/drawable-xxxhdpi/movie_4.png and b/lection03/app/src/main/res/drawable-xxxhdpi/movie_4.png differ diff --git a/lection03/app/src/main/res/drawable-xxxhdpi/movie_5.png b/lection03/app/src/main/res/drawable-xxxhdpi/movie_5.png old mode 100755 new mode 100644 index 52ed058..67cfdb5 Binary files a/lection03/app/src/main/res/drawable-xxxhdpi/movie_5.png and b/lection03/app/src/main/res/drawable-xxxhdpi/movie_5.png differ diff --git a/lection03/app/src/main/res/drawable-xxxhdpi/movie_6.png b/lection03/app/src/main/res/drawable-xxxhdpi/movie_6.png old mode 100755 new mode 100644 index be3124f..2980186 Binary files a/lection03/app/src/main/res/drawable-xxxhdpi/movie_6.png and b/lection03/app/src/main/res/drawable-xxxhdpi/movie_6.png differ diff --git a/lection03/app/src/main/res/drawable-xxxhdpi/movie_7.png b/lection03/app/src/main/res/drawable-xxxhdpi/movie_7.png old mode 100755 new mode 100644 index e54b995..d340c4c Binary files a/lection03/app/src/main/res/drawable-xxxhdpi/movie_7.png and b/lection03/app/src/main/res/drawable-xxxhdpi/movie_7.png differ diff --git a/lection03/app/src/main/res/drawable/ic_camera_indoor_24px.xml b/lection03/app/src/main/res/drawable/ic_camera_indoor_24px.xml new file mode 100644 index 0000000..c030ec4 --- /dev/null +++ b/lection03/app/src/main/res/drawable/ic_camera_indoor_24px.xml @@ -0,0 +1,9 @@ + + + diff --git a/lection03/app/src/main/res/layout/activity_content.xml b/lection03/app/src/main/res/layout/activity_content.xml new file mode 100644 index 0000000..ce3e720 --- /dev/null +++ b/lection03/app/src/main/res/layout/activity_content.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/lection03/app/src/main/res/layout/activity_main.xml b/lection03/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..694aaf3 --- /dev/null +++ b/lection03/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/lection03/app/src/main/res/layout/activity_two_panel.xml b/lection03/app/src/main/res/layout/activity_two_panel.xml new file mode 100644 index 0000000..30ac08e --- /dev/null +++ b/lection03/app/src/main/res/layout/activity_two_panel.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/lection03/app/src/main/res/mipmap-hdpi/ic_launcher.png b/lection03/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..a571e60 Binary files /dev/null and b/lection03/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/lection03/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/lection03/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..61da551 Binary files /dev/null and b/lection03/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/lection03/app/src/main/res/mipmap-mdpi/ic_launcher.png b/lection03/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c41dd28 Binary files /dev/null and b/lection03/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/lection03/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/lection03/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db5080a Binary files /dev/null and b/lection03/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/lection03/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/lection03/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..6dba46d Binary files /dev/null and b/lection03/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/lection03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/lection03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..da31a87 Binary files /dev/null and b/lection03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/lection03/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/lection03/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..15ac681 Binary files /dev/null and b/lection03/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/lection03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/lection03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b216f2d Binary files /dev/null and b/lection03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/lection03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..f25a419 Binary files /dev/null and b/lection03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/lection03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/lection03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e96783c Binary files /dev/null and b/lection03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/lection03/app/src/main/res/values-en/strings.xml b/lection03/app/src/main/res/values-en/strings.xml new file mode 100644 index 0000000..3de1a39 --- /dev/null +++ b/lection03/app/src/main/res/values-en/strings.xml @@ -0,0 +1,3 @@ + + My Application + \ No newline at end of file diff --git a/lection03/app/src/main/res/values-land/colors.xml b/lection03/app/src/main/res/values-land/colors.xml new file mode 100644 index 0000000..8ffa6fa --- /dev/null +++ b/lection03/app/src/main/res/values-land/colors.xml @@ -0,0 +1,13 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + + + #ff0000 + \ No newline at end of file diff --git a/lection03/app/src/main/res/values/strings.xml b/lection03/app/src/main/res/values/strings.xml deleted file mode 100644 index 5b1c3eb..0000000 --- a/lection03/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - hello_world - \ No newline at end of file diff --git a/lection03/app/src/test/java/com/example/myapplication/ExampleUnitTest.kt b/lection03/app/src/test/java/com/example/myapplication/ExampleUnitTest.kt new file mode 100644 index 0000000..e500fb8 --- /dev/null +++ b/lection03/app/src/test/java/com/example/myapplication/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.myapplication + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/lection03/gradle/wrapper/gradle-wrapper.jar b/lection03/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c..0000000 Binary files a/lection03/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/lection03/gradlew.bat b/lection03/gradlew.bat deleted file mode 100644 index ac1b06f..0000000 --- a/lection03/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/lection03/settings.gradle b/lection03/settings.gradle deleted file mode 100644 index 5318e56..0000000 --- a/lection03/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) - repositories { - google() - mavenCentral() - jcenter() // Warning: this repository is going to shut down soon - } -} -rootProject.name = "hello_world" -include ':app' diff --git a/lection02/.gitignore b/lection04/.gitignore similarity index 100% rename from lection02/.gitignore rename to lection04/.gitignore diff --git a/lection04/.idea/.gitignore b/lection04/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/lection04/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/lection04/.idea/codeStyles/Project.xml b/lection04/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..3c7772a --- /dev/null +++ b/lection04/.idea/codeStyles/Project.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/lection04/.idea/codeStyles/codeStyleConfig.xml b/lection04/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/lection04/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/lection03/.idea/compiler.xml b/lection04/.idea/compiler.xml similarity index 75% rename from lection03/.idea/compiler.xml rename to lection04/.idea/compiler.xml index fb7f4a8..61a9130 100644 --- a/lection03/.idea/compiler.xml +++ b/lection04/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/lection04/.idea/gradle.xml b/lection04/.idea/gradle.xml new file mode 100644 index 0000000..18de3ac --- /dev/null +++ b/lection04/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/lection04/.idea/jarRepositories.xml b/lection04/.idea/jarRepositories.xml new file mode 100644 index 0000000..a5f05cd --- /dev/null +++ b/lection04/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lection03/.idea/misc.xml b/lection04/.idea/misc.xml similarity index 63% rename from lection03/.idea/misc.xml rename to lection04/.idea/misc.xml index bdd9278..d5d35ec 100644 --- a/lection03/.idea/misc.xml +++ b/lection04/.idea/misc.xml @@ -1,7 +1,6 @@ - - + diff --git a/lection04/app/.gitignore b/lection04/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/lection04/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/lection04/app/build.gradle b/lection04/app/build.gradle new file mode 100644 index 0000000..19e3a43 --- /dev/null +++ b/lection04/app/build.gradle @@ -0,0 +1,50 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'com.google.gms.google-services' +} + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.3" + + defaultConfig { + applicationId "com.mycompany.servicesexample" + minSdkVersion 22 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.core:core-ktx:1.3.2' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation "androidx.work:work-runtime-ktx:2.5.0" + implementation platform('com.google.firebase:firebase-bom:26.8.0') + implementation 'com.google.firebase:firebase-messaging-ktx' + implementation 'com.google.firebase:firebase-analytics-ktx' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' +} \ No newline at end of file diff --git a/lection04/app/google-services.json b/lection04/app/google-services.json new file mode 100644 index 0000000..4bb7ade --- /dev/null +++ b/lection04/app/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "796625484107", + "project_id": "servicesexample-19226", + "storage_bucket": "servicesexample-19226.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:796625484107:android:45a19f54c8fa44211950ce", + "android_client_info": { + "package_name": "com.mycompany.servicesexample" + } + }, + "oauth_client": [ + { + "client_id": "796625484107-orunt6elud54lr4evfdok3p16be6sekr.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyDkmTng13c_R8CYs5eU6doM2Uj0uVkQlNA" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "796625484107-orunt6elud54lr4evfdok3p16be6sekr.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/lection04/app/proguard-rules.pro b/lection04/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/lection04/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/lection04/app/src/androidTest/java/com/mycompany/servicesexample/ExampleInstrumentedTest.kt b/lection04/app/src/androidTest/java/com/mycompany/servicesexample/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..9cb2f6b --- /dev/null +++ b/lection04/app/src/androidTest/java/com/mycompany/servicesexample/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.mycompany.servicesexample + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.mycompany.servicesexample", appContext.packageName) + } +} \ No newline at end of file diff --git a/lection04/app/src/main/AndroidManifest.xml b/lection04/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..642bebd --- /dev/null +++ b/lection04/app/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lection04/app/src/main/java/com/mycompany/servicesexample/MainActivity.kt b/lection04/app/src/main/java/com/mycompany/servicesexample/MainActivity.kt new file mode 100644 index 0000000..8dcd71d --- /dev/null +++ b/lection04/app/src/main/java/com/mycompany/servicesexample/MainActivity.kt @@ -0,0 +1,50 @@ +package com.mycompany.servicesexample + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import com.google.android.gms.tasks.OnCompleteListener +import com.google.firebase.messaging.FirebaseMessaging + +class MainActivity : AppCompatActivity() { + private val tag = MainActivity::class.java.name + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + +// val work = OneTimeWorkRequestBuilder() +// .setBackoffCriteria() +// .build() +// +// WorkManager.getInstance(this) + + val intent = Intent(this, MyService::class.java) +// startService(intent) +// startService(intent) +// startService(intent) +// startService(intent) +// startService(intent) +// startService(intent) +// startService(intent) +// startService(intent) + + ContextCompat.startForegroundService(this, intent) + + +// FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task -> +// if (!task.isSuccessful) { +// Log.e(tag, "Fetching FCM registration token failed", task.exception) +// return@OnCompleteListener +// } +// +// val token = task.result +// Log.d(tag, "get token = $token") +// }) + + } +} \ No newline at end of file diff --git a/lection04/app/src/main/java/com/mycompany/servicesexample/MyFirebaseMessagingService.kt b/lection04/app/src/main/java/com/mycompany/servicesexample/MyFirebaseMessagingService.kt new file mode 100644 index 0000000..6fcbfc3 --- /dev/null +++ b/lection04/app/src/main/java/com/mycompany/servicesexample/MyFirebaseMessagingService.kt @@ -0,0 +1,18 @@ +package com.mycompany.servicesexample + +import android.util.Log +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage + +class MyFirebaseMessagingService : FirebaseMessagingService() { + + override fun onNewToken(token: String) { + super.onNewToken(token) + Log.d("!!!", "New token $token") + } + + override fun onMessageReceived(message: RemoteMessage) { + super.onMessageReceived(message) + Log.d("!!!", "onMessageReceived $message") + } +} \ No newline at end of file diff --git a/lection04/app/src/main/java/com/mycompany/servicesexample/MyService.kt b/lection04/app/src/main/java/com/mycompany/servicesexample/MyService.kt new file mode 100644 index 0000000..6e144ee --- /dev/null +++ b/lection04/app/src/main/java/com/mycompany/servicesexample/MyService.kt @@ -0,0 +1,76 @@ +package com.mycompany.servicesexample + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.util.Log +import androidx.core.app.NotificationCompat + +class MyService : Service() { + + private val tag = "MyService" + private var started = false + private val channel = "MyChannel2" + private val id = 111 + + + + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + Log.d(tag, "onStartCommand intent = $intent, flags = $flags, startId = $startId") + + if (!started) { + Thread(Runnable { + var i = 0 + while (true) { + Log.d(tag, "New count = $i") + Thread.sleep(1000) + i++ + } + }).start() + started = true + } + + Log.d(tag, "CREATE NOTIF") + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + val channel = + NotificationChannel(channel, "My channel", NotificationManager.IMPORTANCE_MIN) + val notificationService: NotificationManager = + getSystemService(NOTIFICATION_SERVICE) as NotificationManager + notificationService.createNotificationChannel(channel) + } + +// val style = NotificationCompat.BigTextStyle() +// .setBigContentTitle("BIG CONTENT TITLE") +// .setSummaryText("SUMMARY") + + val notification = NotificationCompat.Builder(this, channel) + .setContentTitle("I'm doing job") + .setContentText("sdkljhaskjdfhjkasdhfjadskhfkjasdhfkahsdkjfhadskjhfkasdjhfadskjfhkalsdjhfadskjhfkajdshfjkasdhfkjalsdhfkjladshflkajsdfhjkasdhfjkasdhfjkashdfksdahfkjl") + .setPriority(NotificationCompat.PRIORITY_LOW) + .setSmallIcon(R.drawable.ic_launcher_foreground) +// .setStyle(style) + .build() + + startForeground(id, notification) + + return START_STICKY + } + + override fun onDestroy() { + super.onDestroy() + Log.d(tag, "onDestroy") + } + + override fun onCreate() { + super.onCreate() + Log.d(tag, "onCreate thread ${Thread.currentThread().name}") + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } +} \ No newline at end of file diff --git a/lection04/app/src/main/java/com/mycompany/servicesexample/MyWorker.kt b/lection04/app/src/main/java/com/mycompany/servicesexample/MyWorker.kt new file mode 100644 index 0000000..fab2609 --- /dev/null +++ b/lection04/app/src/main/java/com/mycompany/servicesexample/MyWorker.kt @@ -0,0 +1,21 @@ +package com.mycompany.servicesexample + +import android.content.Context +import android.util.Log +import androidx.work.Worker +import androidx.work.WorkerParameters + +class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { + + private val tag = "MyWorker" + + override fun doWork(): Result { + var i = 0; + while (i < 5) { + Log.d(tag, "New count = $i") + Thread.sleep(1000) + i++ + } + return Result.success() + } +} \ No newline at end of file diff --git a/lection02/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/lection04/app/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from lection02/app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to lection04/app/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/lection02/app/src/main/res/drawable/ic_launcher_background.xml b/lection04/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from lection02/app/src/main/res/drawable/ic_launcher_background.xml rename to lection04/app/src/main/res/drawable/ic_launcher_background.xml diff --git a/lection04/app/src/main/res/layout/activity_main.xml b/lection04/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..4fc2444 --- /dev/null +++ b/lection04/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/lection04/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/lection04/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/lection04/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/lection04/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/lection04/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/lection04/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/lection04/app/src/main/res/mipmap-hdpi/ic_launcher.png b/lection04/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..a571e60 Binary files /dev/null and b/lection04/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/lection04/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/lection04/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..61da551 Binary files /dev/null and b/lection04/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/lection04/app/src/main/res/mipmap-mdpi/ic_launcher.png b/lection04/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c41dd28 Binary files /dev/null and b/lection04/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/lection04/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/lection04/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db5080a Binary files /dev/null and b/lection04/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/lection04/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/lection04/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..6dba46d Binary files /dev/null and b/lection04/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/lection04/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/lection04/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..da31a87 Binary files /dev/null and b/lection04/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/lection04/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/lection04/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..15ac681 Binary files /dev/null and b/lection04/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/lection04/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/lection04/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b216f2d Binary files /dev/null and b/lection04/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/lection04/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection04/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..f25a419 Binary files /dev/null and b/lection04/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/lection04/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/lection04/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e96783c Binary files /dev/null and b/lection04/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/lection06/app/src/main/res/values-night/themes.xml b/lection04/app/src/main/res/values-night/themes.xml similarity index 88% rename from lection06/app/src/main/res/values-night/themes.xml rename to lection04/app/src/main/res/values-night/themes.xml index 7c0cfc0..c835139 100644 --- a/lection06/app/src/main/res/values-night/themes.xml +++ b/lection04/app/src/main/res/values-night/themes.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/lection04/app/src/test/java/com/mycompany/servicesexample/ExampleUnitTest.kt b/lection04/app/src/test/java/com/mycompany/servicesexample/ExampleUnitTest.kt new file mode 100644 index 0000000..cdebac3 --- /dev/null +++ b/lection04/app/src/test/java/com/mycompany/servicesexample/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.mycompany.servicesexample + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/lection09/build.gradle b/lection04/build.gradle similarity index 73% rename from lection09/build.gradle rename to lection04/build.gradle index 7653b3e..1e36df7 100644 --- a/lection09/build.gradle +++ b/lection04/build.gradle @@ -1,14 +1,14 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.5.21" + ext.kotlin_version = "1.4.31" repositories { google() - mavenCentral() + jcenter() } dependencies { - classpath 'com.google.gms:google-services:4.3.5' - classpath "com.android.tools.build:gradle:4.2.2" + classpath "com.android.tools.build:gradle:4.1.3" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.5' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -18,8 +18,7 @@ buildscript { allprojects { repositories { google() - mavenCentral() - jcenter() // Warning: this repository is going to shut down soon + jcenter() } } diff --git a/lection04/gradle.properties b/lection04/gradle.properties new file mode 100644 index 0000000..98bed16 --- /dev/null +++ b/lection04/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official \ No newline at end of file diff --git a/lection04/gradle/wrapper/gradle-wrapper.jar b/lection04/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/lection04/gradle/wrapper/gradle-wrapper.jar differ diff --git a/lection02/gradle/wrapper/gradle-wrapper.properties b/lection04/gradle/wrapper/gradle-wrapper.properties similarity index 80% rename from lection02/gradle/wrapper/gradle-wrapper.properties rename to lection04/gradle/wrapper/gradle-wrapper.properties index babdad1..dc4a320 100644 --- a/lection02/gradle/wrapper/gradle-wrapper.properties +++ b/lection04/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Sep 23 13:18:29 MSK 2021 +#Wed Mar 31 19:12:09 MSK 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip diff --git a/lection02/gradlew b/lection04/gradlew old mode 100644 new mode 100755 similarity index 75% rename from lection02/gradlew rename to lection04/gradlew index 4f906e0..cccdd3d --- a/lection02/gradlew +++ b/lection04/gradlew @@ -1,21 +1,5 @@ #!/usr/bin/env sh -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ############################################################################## ## ## Gradle start up script for UN*X @@ -44,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -82,7 +66,6 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -126,11 +109,10 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -156,19 +138,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=`expr $i + 1` + i=$((i+1)) done case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -177,9 +159,14 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=`save "$@"` +APP_ARGS=$(save "$@") # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + exec "$JAVACMD" "$@" diff --git a/lection09/gradlew.bat b/lection04/gradlew.bat similarity index 100% rename from lection09/gradlew.bat rename to lection04/gradlew.bat diff --git a/lection04/settings.gradle b/lection04/settings.gradle new file mode 100644 index 0000000..5896834 --- /dev/null +++ b/lection04/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +rootProject.name = "ServicesExample" \ No newline at end of file diff --git a/lection05/.idea/jarRepositories.xml b/lection05/.idea/jarRepositories.xml new file mode 100644 index 0000000..a5f05cd --- /dev/null +++ b/lection05/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lection05/.idea/misc.xml b/lection05/.idea/misc.xml deleted file mode 100644 index 8beed34..0000000 --- a/lection05/.idea/misc.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/lection05/README.MD b/lection05/README.MD new file mode 100644 index 0000000..7903a4a --- /dev/null +++ b/lection05/README.MD @@ -0,0 +1,6 @@ +# Код для пятой лекции +## Что бы проект заработал: +В проекте используется OpenWeatherMap API. Соответственно требуется: +- Зарегестрироваться на сайте https://openweathermap.org/ +- Взять API ключик из раздела с ключами - https://home.openweathermap.org/api_keys +- Вставить ключ в AuthInterceptor, вместо строки **** \ No newline at end of file diff --git a/lection05/app/build.gradle b/lection05/app/build.gradle deleted file mode 100644 index 3aa077e..0000000 --- a/lection05/app/build.gradle +++ /dev/null @@ -1,43 +0,0 @@ -plugins { - id 'com.android.application' - id 'kotlin-android' -} - -android { - compileSdk 31 - - defaultConfig { - applicationId "ru.mail.education.lesson05" - minSdk 21 - targetSdk 31 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } - - buildFeatures { - viewBinding true - } -} - -dependencies { - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'com.google.android.material:material:1.4.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.1' -} \ No newline at end of file diff --git a/lection05/app/src/main/AndroidManifest.xml b/lection05/app/src/main/AndroidManifest.xml deleted file mode 100644 index 3c78733..0000000 --- a/lection05/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/KoinModules.kt b/lection05/app/src/main/java/ru/hse/lection05/KoinModules.kt new file mode 100644 index 0000000..c64c56f --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/KoinModules.kt @@ -0,0 +1,64 @@ +package ru.hse.lection05 + +import com.google.gson.GsonBuilder +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.koin.core.parameter.parametersOf +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import ru.hse.lection05.businesslayer.repositories.IPlaceRepository +import ru.hse.lection05.businesslayer.repositories.IWeatherRepository +import ru.hse.lection05.businesslayer.repositories.PlaceRepository +import ru.hse.lection05.businesslayer.repositories.WeatherRepository +import ru.hse.lection05.datalayer.accessors.IApiAccessor +import ru.hse.lection05.datalayer.accessors.IOfflineAccessor +import ru.hse.lection05.datalayer.accessors.PaperOfflineAccessor +import ru.hse.lection05.datalayer.interceptors.AuthInterceptor +import ru.hse.lection05.datalayer.interceptors.PreferencesInterceptor +import ru.hse.lection05.objects.Place + +val commonModule = module() { + single { + // Логгер запросов. Его желательно подключать только во время разработки и не оставлять в релизных сборках + val logging = HttpLoggingInterceptor().apply { + setLevel(HttpLoggingInterceptor.Level.BODY) + } + + val client = OkHttpClient.Builder() + .addInterceptor(AuthInterceptor()) + .addInterceptor(PreferencesInterceptor()) + .addNetworkInterceptor(logging) + .build() + + val gson = GsonBuilder() + .create() + + val retrofit = Retrofit.Builder() + .baseUrl("https://api.openweathermap.org/data/2.5/") + .client(client) + .addConverterFactory(GsonConverterFactory.create(gson)) + .build() + + retrofit.create(IApiAccessor::class.java) + } + + + factory> { (name: String) -> + PaperOfflineAccessor(name) + } +} + + +val placeModule = module { + single { + PlaceRepository(get(), get { parametersOf("Place") }) + } +} + + +val weatherModule = module { + single { + WeatherRepository(get()) + } +} diff --git a/lection05/app/src/main/java/ru/hse/lection05/MyApplication.kt b/lection05/app/src/main/java/ru/hse/lection05/MyApplication.kt new file mode 100644 index 0000000..6860279 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/MyApplication.kt @@ -0,0 +1,36 @@ +package ru.hse.lection05 + +import android.app.Application +import io.paperdb.Paper +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin +import ru.hse.lection05.businesslayer.repositories.PlaceRepositoryFactory +import ru.hse.lection05.businesslayer.repositories.RepositoryFactory + +class MyApplication: Application() { + override fun onCreate() { + super.onCreate() + + + // Инициализация DB, для оффлайнового хранения + Paper.init(this) + + + // Пример ручного, самописного, DI + RepositoryFactory.register(PlaceRepositoryFactory()) + + + + // Инициализация KOIN-модулей, для DI + val koinModules = listOf( + commonModule + , placeModule + , weatherModule + ) + + startKoin { + androidContext(this@MyApplication) + modules(koinModules) + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/IPlaceRepository.kt b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/IPlaceRepository.kt new file mode 100644 index 0000000..3340c6c --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/IPlaceRepository.kt @@ -0,0 +1,10 @@ +package ru.hse.lection05.businesslayer.repositories + +import ru.hse.lection05.objects.Place + +interface IPlaceRepository { + fun save(place: Place, callback: (result: Boolean, error: Throwable?) -> Unit) + fun loadAll(callback: (result: List?, error: Throwable?) -> Unit) + + fun find(query: String, callback: (result: List?, error: Throwable?) -> Unit) +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/IWeatherRepository.kt b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/IWeatherRepository.kt new file mode 100644 index 0000000..b08d13b --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/IWeatherRepository.kt @@ -0,0 +1,7 @@ +package ru.hse.lection05.businesslayer.repositories + +import ru.hse.lection05.objects.WeatherData + +interface IWeatherRepository { + fun weather(cityId: Long, callback: (result: WeatherData?, error: Throwable?) -> Unit) +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/OnlyErrorPlaceRepository.kt b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/OnlyErrorPlaceRepository.kt new file mode 100644 index 0000000..516468b --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/OnlyErrorPlaceRepository.kt @@ -0,0 +1,29 @@ +package ru.hse.lection05.businesslayer.repositories + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import ru.hse.lection05.objects.Place + +class OnlyErrorPlaceRepository(): IPlaceRepository { + protected val scope = CoroutineScope(Dispatchers.IO) + + + override fun save(place: Place, callback: (result: Boolean, error: Throwable?) -> Unit) { + scope.launch { + callback(false, IllegalStateException("invoked IPlaceRepository.save")) + } + } + + override fun loadAll(callback: (result: List?, error: Throwable?) -> Unit) { + scope.launch { + callback(null, IllegalStateException("invoked IPlaceRepository.loadAll")) + } + } + + override fun find(query: String, callback: (result: List?, error: Throwable?) -> Unit) { + scope.launch { + callback(null, IllegalStateException("invoked IPlaceRepository.find")) + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/PlaceRepository.kt b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/PlaceRepository.kt new file mode 100644 index 0000000..dea22f2 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/PlaceRepository.kt @@ -0,0 +1,63 @@ +package ru.hse.lection05.businesslayer.repositories + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import ru.hse.lection05.datalayer.accessors.IApiAccessor +import ru.hse.lection05.datalayer.accessors.IOfflineAccessor +import ru.hse.lection05.datalayer.accessors.MemoryCacheAccessor +import ru.hse.lection05.objects.Place + +class PlaceRepository( + val onlineAccessor: IApiAccessor + , val offlineAccessor: IOfflineAccessor +): IPlaceRepository { + protected val scope = CoroutineScope(Dispatchers.IO) + + protected val cacheAccessor = MemoryCacheAccessor() + + + override fun save(place: Place, callback: (result: Boolean, error: Throwable?) -> Unit) { + scope.launch { + try { + callback(offlineAccessor.save(place), null) + } catch (error: Throwable) { + callback(false, error) + } + } + } + + override fun loadAll(callback: (result: List?, error: Throwable?) -> Unit) { + scope.launch { + try { + val cached = offlineAccessor.all()?: emptyList() + val list = cached.toMutableList().apply { + sortBy { it.name } + } + callback(list, null) + } catch (error: Throwable) { + callback(null, error) + } + } + } + + override fun find(query: String, callback: (result: List?, error: Throwable?) -> Unit) { + scope.launch { + try { + val key = "find?query=$query" + val cachedList = cacheAccessor.get(key) + + when (cachedList == null) { + true -> { + val result = onlineAccessor.find(query).list + cacheAccessor.put(key, result) + callback(result, null) + } + false -> callback(cachedList, null) + } + } catch (error: Throwable) { + callback(null, error) + } + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/PlaceRepositoryFactory.kt b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/PlaceRepositoryFactory.kt new file mode 100644 index 0000000..4a32955 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/PlaceRepositoryFactory.kt @@ -0,0 +1,56 @@ +package ru.hse.lection05.businesslayer.repositories + +import com.google.gson.GsonBuilder +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import ru.hse.lection05.datalayer.accessors.IApiAccessor +import ru.hse.lection05.datalayer.accessors.PaperOfflineAccessor +import ru.hse.lection05.datalayer.interceptors.AuthInterceptor +import ru.hse.lection05.datalayer.interceptors.PreferencesInterceptor +import ru.hse.lection05.objects.Place + +class PlaceRepositoryFactory: RepositoryFactory.IFactory { + private val api by lazy { createApi() } + + + override fun acqure(clazz: Class): T? { + return when(clazz) { + IPlaceRepository::class.java -> createPlaceProvider() as T + else -> null + } + } + + private fun createApi(): IApiAccessor { + // Логгер запросов. Его желательно подключать только во время разработки и не оставлять в релизных сборках + val logging = HttpLoggingInterceptor().apply { + setLevel(HttpLoggingInterceptor.Level.BODY) + } + + val client = OkHttpClient.Builder() + .addInterceptor(AuthInterceptor()) + .addInterceptor(PreferencesInterceptor()) + .addNetworkInterceptor(logging) + .build() + + val gson = GsonBuilder() + .create() + + val retrofit = Retrofit.Builder() + .baseUrl("https://api.openweathermap.org/data/2.5/") + .client(client) + .addConverterFactory(GsonConverterFactory.create(gson)) + .build() + + return retrofit.create(IApiAccessor::class.java) + } + + private fun createPlaceProvider(): IPlaceRepository { + val offlineAccessor = PaperOfflineAccessor("Place") + return PlaceRepository(api, offlineAccessor) + + // Или, если хотим на все методы возвращать ошибки: +// return OnlyErrorPlaceRepository() + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/RepositoryFactory.kt b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/RepositoryFactory.kt new file mode 100644 index 0000000..8a8aef2 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/RepositoryFactory.kt @@ -0,0 +1,25 @@ +package ru.hse.lection05.businesslayer.repositories + +object RepositoryFactory { + interface IFactory { + fun acqure(clazz: Class): T? + } + + private val factories = mutableSetOf() + + + fun register(factory: IFactory) { + factories.add(factory) + } + + fun acqure(clazz: Class): T { + factories.forEach { + val tmp = it.acqure(clazz) + if (tmp != null) { + return tmp + } + } + + throw IllegalStateException("cant create implementation: $clazz") + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/WeatherRepository.kt b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/WeatherRepository.kt new file mode 100644 index 0000000..c8dc51d --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/businesslayer/repositories/WeatherRepository.kt @@ -0,0 +1,24 @@ +package ru.hse.lection05.businesslayer.repositories + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import ru.hse.lection05.datalayer.accessors.IApiAccessor +import ru.hse.lection05.objects.WeatherData + +class WeatherRepository( + val onlineAccessor: IApiAccessor +): IWeatherRepository { + protected val scope = CoroutineScope(Dispatchers.IO) + + + override fun weather(cityId: Long, callback: (result: WeatherData?, error: Throwable?) -> Unit) { + scope.launch { + try { + callback(onlineAccessor.weather(cityId), null) + } catch (error: Throwable) { + callback(null, error) + } + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/IApiAccessor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/IApiAccessor.kt new file mode 100644 index 0000000..a3b8a3d --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/IApiAccessor.kt @@ -0,0 +1,15 @@ +package ru.hse.lection05.datalayer.accessors + +import retrofit2.http.GET +import retrofit2.http.Query +import ru.hse.lection05.objects.ApiListResult +import ru.hse.lection05.objects.Place +import ru.hse.lection05.objects.WeatherData + +interface IApiAccessor { + @GET("find") + suspend fun find(@Query("q") query: String): ApiListResult + + @GET("weather") + suspend fun weather(@Query("id") id: Long): WeatherData +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/ICacheAccessor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/ICacheAccessor.kt new file mode 100644 index 0000000..9ee8877 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/ICacheAccessor.kt @@ -0,0 +1,13 @@ +package ru.hse.lection05.datalayer.accessors + +import java.util.concurrent.TimeUnit + +interface ICacheAccessor { + fun get(key: String, maxLiveTimeInMillis: Long = TIME_5_MINUTES): List? + fun put(key: String, list: List?) + + + companion object { + val TIME_5_MINUTES = TimeUnit.MINUTES.toMillis(5) + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/IOfflineAccessor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/IOfflineAccessor.kt new file mode 100644 index 0000000..eef2776 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/IOfflineAccessor.kt @@ -0,0 +1,7 @@ +package ru.hse.lection05.datalayer.accessors + +interface IOfflineAccessor { + fun all(): List? + fun save(item: TYPE): Boolean + fun remove(item: TYPE): Boolean +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/MemoryCacheAccessor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/MemoryCacheAccessor.kt new file mode 100644 index 0000000..9cc6f76 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/MemoryCacheAccessor.kt @@ -0,0 +1,30 @@ +package ru.hse.lection05.datalayer.accessors + +import android.os.SystemClock + +class MemoryCacheAccessor(): ICacheAccessor { + val map = mutableMapOf>>() + + + override fun get(key: String, maxLiveTimeInMillis: Long): List? { + val pair = map[key] + if (pair == null) { + return null + } + + val deltaTime = SystemClock.elapsedRealtime() - pair.first + if (deltaTime > maxLiveTimeInMillis) { + map.remove(key) + return null + } + + return pair.second as List + } + + override fun put(key: String, list: List?) { + when { + list == null -> map.remove(key) + else -> map[key] = Pair(SystemClock.elapsedRealtime(), list) + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/MemoryOfflineAccessor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/MemoryOfflineAccessor.kt new file mode 100644 index 0000000..e656fd4 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/MemoryOfflineAccessor.kt @@ -0,0 +1,12 @@ +package ru.hse.lection05.datalayer.accessors + +import ru.hse.lection05.objects.AbstractObject + +class MemoryOfflineAccessor: IOfflineAccessor { + val keeper = mutableSetOf() + + override fun all() = keeper.toList() + override fun save(item: TYPE) = keeper.add(item) + override fun remove(item: TYPE) = keeper.remove(item) + +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/PaperOfflineAccessor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/PaperOfflineAccessor.kt new file mode 100644 index 0000000..f684af3 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/accessors/PaperOfflineAccessor.kt @@ -0,0 +1,36 @@ +package ru.hse.lection05.datalayer.accessors + +import io.paperdb.Paper +import ru.hse.lection05.objects.AbstractObject + +class PaperOfflineAccessor(val storageName: String): IOfflineAccessor { + override fun all(): List? { + return Paper.book().read(storageName, listOf()) + } + + override fun save(item: TYPE): Boolean { + val list = all()?: emptyList() + val set = list.toMutableSet() + val result = set.add(item) + + + if (result) { + Paper.book().write(storageName, set.toList()) + } + + return result + } + + override fun remove(item: TYPE): Boolean { + val list = all()?: emptyList() + val set = list.toMutableSet() + val result = set.remove(item) + + + if (result) { + Paper.book().write(storageName, set.toList()) + } + + return result + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/interceptors/AuthInterceptor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/interceptors/AuthInterceptor.kt new file mode 100644 index 0000000..85ee5e8 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/interceptors/AuthInterceptor.kt @@ -0,0 +1,27 @@ +package ru.hse.lection05.datalayer.interceptors + +import okhttp3.Interceptor +import okhttp3.Response + +class AuthInterceptor: Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val originalRequest = chain.request() + + val newUrl = originalRequest.url + .newBuilder() + .addQueryParameter("appid", API_KEY) + .build() + + val newRequest = originalRequest + .newBuilder() + .url(newUrl) + .build() + + return chain.proceed(newRequest) + } + + + companion object { + const val API_KEY = "" + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/datalayer/interceptors/PreferencesInterceptor.kt b/lection05/app/src/main/java/ru/hse/lection05/datalayer/interceptors/PreferencesInterceptor.kt new file mode 100644 index 0000000..e5f651e --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/datalayer/interceptors/PreferencesInterceptor.kt @@ -0,0 +1,23 @@ +package ru.hse.lection05.datalayer.interceptors + +import okhttp3.Interceptor +import okhttp3.Response + +class PreferencesInterceptor: Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val originalRequest = chain.request() + + val newUrl = originalRequest.url + .newBuilder() + .addQueryParameter("units", "metric") + .addQueryParameter("lang", "ru") + .build() + + val newRequest = originalRequest + .newBuilder() + .url(newUrl) + .build() + + return chain.proceed(newRequest) + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/AbstractObject.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/AbstractObject.kt new file mode 100644 index 0000000..ad61cfa --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/AbstractObject.kt @@ -0,0 +1,6 @@ +package ru.hse.lection05.objects + +import java.io.Serializable + +abstract class AbstractObject: Serializable { +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/ApiListResult.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/ApiListResult.kt new file mode 100644 index 0000000..cd36f1e --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/ApiListResult.kt @@ -0,0 +1,10 @@ +package ru.hse.lection05.objects + +import com.google.gson.annotations.SerializedName + +class ApiListResult { + @SerializedName("message") var message = "" + @SerializedName("cod") var cod = "" + @SerializedName("count") var count = 0 + @SerializedName("list") var list = emptyList() +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/Coord.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/Coord.kt new file mode 100644 index 0000000..2f6e292 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/Coord.kt @@ -0,0 +1,8 @@ +package ru.hse.lection05.objects + +import com.google.gson.annotations.SerializedName + +class Coord: AbstractObject() { + @SerializedName("lat") var lat = 0.0 + @SerializedName("lon") var lon = 0.0 +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/Main.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/Main.kt new file mode 100644 index 0000000..6e1d644 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/Main.kt @@ -0,0 +1,7 @@ +package ru.hse.lection05.objects + +import com.google.gson.annotations.SerializedName + +class Main: AbstractObject() { + @SerializedName("temp") var temp = 0.0 +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/Place.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/Place.kt new file mode 100644 index 0000000..61f1d99 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/Place.kt @@ -0,0 +1,24 @@ +package ru.hse.lection05.objects + +import com.google.gson.annotations.SerializedName + +class Place: AbstractObject() { + @SerializedName("id") var id = 0L + @SerializedName("name") var name = "" + + @SerializedName("coord") var coord: Coord? = null + @SerializedName("sys") var sys: Sys? = null + + + override fun hashCode(): Int { + return id.hashCode() + } + + override fun equals(other: Any?): Boolean { + return other is Place + && other.id == id + } + + + +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/Sys.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/Sys.kt new file mode 100644 index 0000000..4854227 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/Sys.kt @@ -0,0 +1,8 @@ +package ru.hse.lection05.objects + +import com.google.gson.annotations.SerializedName + + +class Sys: AbstractObject() { + @SerializedName("country") var country = "" +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/Weather.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/Weather.kt new file mode 100644 index 0000000..f311324 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/Weather.kt @@ -0,0 +1,10 @@ +package ru.hse.lection05.objects + +import com.google.gson.annotations.SerializedName + +class Weather: AbstractObject() { + @SerializedName("id") var id = 0L + @SerializedName("main") var main = "" + @SerializedName("description") var description = "" + @SerializedName("icon") var icon = "" +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/objects/WeatherData.kt b/lection05/app/src/main/java/ru/hse/lection05/objects/WeatherData.kt new file mode 100644 index 0000000..c7014c6 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/objects/WeatherData.kt @@ -0,0 +1,22 @@ +package ru.hse.lection05.objects + +import com.google.gson.annotations.SerializedName + +class WeatherData: AbstractObject() { + @SerializedName("id") var id = 0L + @SerializedName("name") var name = "" + + @SerializedName("weather") var weather = emptyList() + @SerializedName("main") var main: Main? = null + + + + override fun hashCode(): Int { + return id.hashCode() + } + + override fun equals(other: Any?): Boolean { + return other is WeatherData + && other.id == id + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/States.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/States.kt new file mode 100644 index 0000000..58b0f17 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/States.kt @@ -0,0 +1,7 @@ +package ru.hse.lection05.presentationlayer + +sealed class States + +data class Success(val result: RESULT): States() +data class Fail(val error: Throwable?): States() +data class Pending(val attempt: Int = 1): States() \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/activities/MainActivity.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/activities/MainActivity.kt new file mode 100644 index 0000000..0a52a4d --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/activities/MainActivity.kt @@ -0,0 +1,41 @@ +package ru.hse.lection05.presentationlayer.activities + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import ru.hse.lection05.R +import ru.hse.lection05.presentationlayer.fragments.INavigator +import ru.hse.lection05.presentationlayer.fragments.PlaceAddFragment +import ru.hse.lection05.presentationlayer.fragments.PlaceListFragment +import ru.hse.lection05.presentationlayer.fragments.SplashFragment + +class MainActivity : AppCompatActivity(), INavigator { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.activity_main) + + + if (savedInstanceState == null) { + supportFragmentManager.beginTransaction() + .replace(R.id.container, SplashFragment(), "SPLASH") + .commit() + } + } + + override fun mainScreen() { + supportFragmentManager.beginTransaction() + .replace(R.id.container, PlaceListFragment(), "PLACES") + .commit() + } + + override fun findPlaceScreen() { + supportFragmentManager.beginTransaction() + .replace(R.id.container, PlaceAddFragment(), "ADD") + .addToBackStack(null) + .commit() + } + + override fun pop() { + supportFragmentManager.popBackStack() + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/AbstractAdapter.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/AbstractAdapter.kt new file mode 100644 index 0000000..02dd747 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/AbstractAdapter.kt @@ -0,0 +1,27 @@ +package ru.hse.lection05.presentationlayer.adapters + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import ru.hse.lection05.objects.AbstractObject +import ru.hse.lection05.presentationlayer.adapters.holders.AbstractHolder + +abstract class AbstractAdapter(calculator: DiffUtil.ItemCallback<*>) + : ListAdapter>(calculator as DiffUtil.ItemCallback) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractHolder<*> { + throw IllegalArgumentException("Can't handle ViewType: $viewType") + } + + override fun onBindViewHolder(holder: AbstractHolder<*>, position: Int) { + val item = getItem(position) + holder.bind(item) + } + + + protected fun inflate(layoutId: Int, view: ViewGroup): View { + return LayoutInflater.from(view.context).inflate(layoutId, view, false) + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/PlacesAdapter.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/PlacesAdapter.kt new file mode 100644 index 0000000..56c19f7 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/PlacesAdapter.kt @@ -0,0 +1,44 @@ +package ru.hse.lection05.presentationlayer.adapters + +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.DiffUtil +import androidx.viewpager2.adapter.FragmentStateAdapter +import ru.hse.lection05.presentationlayer.fragments.PlaceFragment +import ru.hse.lection05.objects.Place + +class PlacesAdapter(fragment: Fragment): FragmentStateAdapter(fragment) { + protected var pages = listOf() + + + override fun getItemCount() = pages.size + + override fun createFragment(position: Int): Fragment { + val place = pages[position] + return PlaceFragment.newInstance(place) + } + + + fun submitList(list: List) { + val result = Calculator(pages, list).execute() + pages = list + + result.dispatchUpdatesTo(this) + } + + + protected class Calculator(val oldList: List, val newList: List): DiffUtil.Callback() { + override fun getOldListSize() = oldList.size + override fun getNewListSize() = newList.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldList[oldItemPosition].id == newList[newItemPosition].id + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldList[oldItemPosition] == newList[newItemPosition] + } + + + fun execute() = DiffUtil.calculateDiff(this, true) + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/SuggestPlaceAdapter.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/SuggestPlaceAdapter.kt new file mode 100644 index 0000000..03cf082 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/SuggestPlaceAdapter.kt @@ -0,0 +1,16 @@ +package ru.hse.lection05.presentationlayer.adapters + +import android.view.ViewGroup +import ru.hse.lection05.R +import ru.hse.lection05.presentationlayer.adapters.calculators.PlaceCalculator +import ru.hse.lection05.presentationlayer.adapters.holders.AbstractHolder +import ru.hse.lection05.presentationlayer.adapters.holders.SuggestPlaceHolder + +class SuggestPlaceAdapter(val listener: IListener): AbstractAdapter(PlaceCalculator()) { + interface IListener: SuggestPlaceHolder.IListener + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractHolder<*> { + return SuggestPlaceHolder(inflate(R.layout.item_suggest_place, parent), listener) + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/calculators/PlaceCalculator.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/calculators/PlaceCalculator.kt new file mode 100644 index 0000000..e1e9d27 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/calculators/PlaceCalculator.kt @@ -0,0 +1,9 @@ +package ru.hse.lection05.presentationlayer.adapters.calculators + +import ru.hse.lection05.objects.Place + +class PlaceCalculator: SimpleCalculator() { + override fun areItemsTheSame(oldItem: Place, newItem: Place): Boolean { + return oldItem.id == newItem.id + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/calculators/SimpleCalculator.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/calculators/SimpleCalculator.kt new file mode 100644 index 0000000..8fa125a --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/calculators/SimpleCalculator.kt @@ -0,0 +1,14 @@ +package ru.hse.lection05.presentationlayer.adapters.calculators + +import androidx.recyclerview.widget.DiffUtil +import ru.hse.lection05.objects.AbstractObject + +open class SimpleCalculator: DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: ITEM, newItem: ITEM): Boolean { + return oldItem::class == newItem::class + } + + override fun areContentsTheSame(oldItem: ITEM, newItem: ITEM): Boolean { + return oldItem.equals(newItem) + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/holders/AbstractHolder.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/holders/AbstractHolder.kt new file mode 100644 index 0000000..f25f84b --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/holders/AbstractHolder.kt @@ -0,0 +1,19 @@ +package ru.hse.lection05.presentationlayer.adapters.holders + +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +abstract class AbstractHolder(view: View): RecyclerView.ViewHolder(view) { + var item: ITEM? = null + + + fun bind(newItem: Any?) { + item = newItem as? ITEM + bindView(item) + } + + abstract fun bindView(item: ITEM?) + + + protected fun findViewById(resourceId: Int) = itemView.findViewById(resourceId) +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/holders/SuggestPlaceHolder.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/holders/SuggestPlaceHolder.kt new file mode 100644 index 0000000..27bcf88 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/adapters/holders/SuggestPlaceHolder.kt @@ -0,0 +1,27 @@ +package ru.hse.lection05.presentationlayer.adapters.holders + +import android.view.View +import android.widget.TextView +import ru.hse.lection05.R +import ru.hse.lection05.objects.Place + +class SuggestPlaceHolder(view: View, val listener: IListener): AbstractHolder(view) { + interface IListener { + fun onSuggestClicked(item: Place) + } + + + val title by lazy { findViewById(R.id.title) } + val subtitle by lazy { findViewById(R.id.subtitle) } + + + init { + itemView.setOnClickListener { listener.onSuggestClicked(item!!) } + } + + + override fun bindView(item: Place?) { + title.text = item?.name + subtitle.text = item?.sys?.country + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/AbstractFragment.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/AbstractFragment.kt new file mode 100644 index 0000000..957decd --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/AbstractFragment.kt @@ -0,0 +1,15 @@ +package ru.hse.lection05.presentationlayer.fragments + +import androidx.fragment.app.Fragment + +abstract class AbstractFragment: Fragment() { + fun navigator(): INavigator { + var nvaigator = parentFragment as? INavigator + + if (nvaigator == null) { + nvaigator = requireActivity() as? INavigator + } + + return nvaigator!! + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/INavigator.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/INavigator.kt new file mode 100644 index 0000000..0203472 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/INavigator.kt @@ -0,0 +1,7 @@ +package ru.hse.lection05.presentationlayer.fragments + +interface INavigator { + fun mainScreen() + fun findPlaceScreen() + fun pop() +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceAddFragment.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceAddFragment.kt new file mode 100644 index 0000000..0e14b2a --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceAddFragment.kt @@ -0,0 +1,93 @@ +package ru.hse.lection05.presentationlayer.fragments + +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.text.Editable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import android.widget.TextView +import android.widget.Toast +import androidx.core.view.isVisible +import androidx.core.widget.addTextChangedListener +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import ru.hse.lection05.R +import ru.hse.lection05.presentationlayer.Fail +import ru.hse.lection05.presentationlayer.Pending +import ru.hse.lection05.presentationlayer.Success +import ru.hse.lection05.presentationlayer.models.PlaceViewModel +import ru.hse.lection05.presentationlayer.models.SearchViewModel +import ru.hse.lection05.objects.Place +import ru.hse.lection05.presentationlayer.adapters.SuggestPlaceAdapter + +class PlaceAddFragment: AbstractFragment(), SuggestPlaceAdapter.IListener { + protected val viewModel by activityViewModels() + protected val searchViewModel by viewModels() + + val handler = Handler(Looper.getMainLooper()) + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.content_place_add, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val suggestAdapter = SuggestPlaceAdapter(this) + view.findViewById(R.id.recycler).apply { + adapter = suggestAdapter + layoutManager = LinearLayoutManager(context) + } + + view.findViewById(R.id.query).apply { + addTextChangedListener(afterTextChanged = ::onQueryChanged) + } + + val message = view.findViewById(R.id.message).apply { + setOnClickListener { searchViewModel.retry() } + } + + val progress = view.findViewById(R.id.progress) + searchViewModel.searchResult().observe(viewLifecycleOwner) { + progress.isVisible = it is Pending + + message.text = (it as? Fail)?.error?.message + message.isVisible = it is Fail + + when (it is Success) { + true -> suggestAdapter.submitList(it.result) + false -> suggestAdapter.submitList(emptyList()) + } + } + } + + override fun onDestroyView() { + super.onDestroyView() + } + + override fun onSuggestClicked(item: Place) { + viewModel.save(item) { result, error -> + when (result) { + true -> navigator().pop() + false -> Toast.makeText(requireContext(), error?.message?: "UNKNOWN", Toast.LENGTH_LONG).show() + } + } + } + + + protected fun onQueryChanged(text: Editable?) { + handler.removeCallbacksAndMessages(null) + handler.postDelayed( { searchViewModel.updateQuery(text.toString()) }, 600) + } +} + + + + + diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceFragment.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceFragment.kt new file mode 100644 index 0000000..a59eb45 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceFragment.kt @@ -0,0 +1,80 @@ +package ru.hse.lection05.presentationlayer.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import ru.hse.lection05.R +import ru.hse.lection05.presentationlayer.Fail +import ru.hse.lection05.presentationlayer.Pending +import ru.hse.lection05.presentationlayer.Success +import ru.hse.lection05.presentationlayer.models.WeatherViewModel +import ru.hse.lection05.objects.Place + +class PlaceFragment: AbstractFragment() { + val placeViewModel by viewModels() + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + inflater.inflate(R.layout.content_place, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + + val place = arguments?.getSerializable(EXTRAS_PLACE) as Place + placeViewModel.load(place) + + + val progress = view.findViewById(R.id.progress) + val temp = view.findViewById(R.id.temp) + val weather = view.findViewById(R.id.weather) + + val message = view.findViewById(R.id.message).apply { + setOnClickListener { placeViewModel.load(place) } + } + + val title = view.findViewById(R.id.title) + title.text = place.name + + placeViewModel.weatherData().observe(viewLifecycleOwner) { + progress.isVisible = it is Pending + message.isVisible = it is Fail + + when (it) { + is Success -> { + title.text = it.result.name + temp.text = it.result.main?.temp.toString() + weather.text = it.result.weather.firstOrNull()?.description + } + + is Fail -> { + message.text = it.error?.message + } + } + } + + } + + + companion object { + const val TAG = "PlaceFragment" + + const val EXTRAS_PLACE = "EXTRAS.PLACE" + + + fun newInstance(place: Place): Fragment { + val extras = Bundle().apply { + putSerializable(EXTRAS_PLACE, place) + } + + return PlaceFragment().apply { + arguments = extras + } + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceListFragment.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceListFragment.kt new file mode 100644 index 0000000..589fa91 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/PlaceListFragment.kt @@ -0,0 +1,62 @@ +package ru.hse.lection05.presentationlayer.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels +import androidx.viewpager2.widget.ViewPager2 +import ru.hse.lection05.R +import ru.hse.lection05.presentationlayer.Fail +import ru.hse.lection05.presentationlayer.Pending +import ru.hse.lection05.presentationlayer.Success +import ru.hse.lection05.presentationlayer.models.PlaceViewModel +import ru.hse.lection05.presentationlayer.adapters.PlacesAdapter + +class PlaceListFragment: AbstractFragment() { + protected val viewModel by activityViewModels() + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.contetn_places, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + view.findViewById(R.id.fab).setOnClickListener { + navigator().findPlaceScreen() + } + + val placeAdapter = PlacesAdapter(this) + view.findViewById(R.id.recycler).apply { + adapter = placeAdapter + } + + val stub = view.findViewById(R.id.stub) + val progress = view.findViewById(R.id.progress) + viewModel.places().observe(viewLifecycleOwner) { + progress.isVisible = it is Pending + + when(it) { + is Success -> { + placeAdapter.submitList(it.result) + + if (it.result.isEmpty()) { + stub.text = "No local places" + } else { + stub.text = null + } + } + is Fail -> stub.text = "error: ${it.error}" + } + } + } +} + + + + + diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/SplashFragment.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/SplashFragment.kt new file mode 100644 index 0000000..57e2897 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/fragments/SplashFragment.kt @@ -0,0 +1,45 @@ +package ru.hse.lection05.presentationlayer.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import ru.hse.lection05.R +import ru.hse.lection05.presentationlayer.presenters.PlacePresenter +import ru.hse.lection05.presentationlayer.views.IPlaceView + +class SplashFragment: AbstractFragment(), IPlaceView { + protected val presenter = PlacePresenter() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.contetn_splash, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + presenter.attachView(this) + } + + override fun onStart() { + super.onStart() + + presenter.startTimer() + } + + + override fun onDestroyView() { + super.onDestroyView() + + presenter.detachView(this) + } + + override fun nextStep() { + navigator().mainScreen() + } +} + + + + + diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/PlaceViewModel.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/PlaceViewModel.kt new file mode 100644 index 0000000..75643e3 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/PlaceViewModel.kt @@ -0,0 +1,42 @@ +package ru.hse.lection05.presentationlayer.models + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.launch +import ru.hse.lection05.businesslayer.repositories.IPlaceRepository +import ru.hse.lection05.businesslayer.repositories.RepositoryFactory +import ru.hse.lection05.presentationlayer.Fail +import ru.hse.lection05.presentationlayer.Pending +import ru.hse.lection05.presentationlayer.States +import ru.hse.lection05.presentationlayer.Success +import ru.hse.lection05.objects.Place + +class PlaceViewModel: ViewModel() { + protected val repository by lazy { RepositoryFactory.acqure(IPlaceRepository::class.java) } + + + fun places(): LiveData>> { + val liveData = MutableLiveData>>().apply { + postValue(Pending()) + } + + repository.loadAll { result, error -> + val state = when { + result == null -> Fail(error) + else -> Success(result) + } + + liveData.postValue(state) + } + + return liveData + } + + fun save(item: Place, callback: (result: Boolean, error: Throwable?) -> Unit) { + repository.save(item) { result, error -> + viewModelScope.launch { callback(result, error) } + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/SearchViewModel.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/SearchViewModel.kt new file mode 100644 index 0000000..1da328c --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/SearchViewModel.kt @@ -0,0 +1,59 @@ +package ru.hse.lection05.presentationlayer.models + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import org.koin.core.component.KoinApiExtension +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import ru.hse.lection05.businesslayer.repositories.IPlaceRepository +import ru.hse.lection05.presentationlayer.Fail +import ru.hse.lection05.presentationlayer.Pending +import ru.hse.lection05.presentationlayer.States +import ru.hse.lection05.presentationlayer.Success +import ru.hse.lection05.objects.Place + +@KoinApiExtension +class SearchViewModel: ViewModel(), KoinComponent { + protected val provider by inject() // вставка при помощи KOIN модуля + protected val searchResult = MutableLiveData>>().apply { + postValue(Success(emptyList())) + } + + protected var currentQuery = "" + + + fun searchResult(): LiveData>> = searchResult + + fun updateQuery(query: String) { + if (currentQuery == query) { + return + } + currentQuery = query + + execute() + } + + fun retry() { + execute() + } + + protected fun execute() { + searchResult.postValue(Pending()) + + when (currentQuery.isEmpty()) { + true -> searchResult.postValue(Success(emptyList())) + + false -> { + provider.find(currentQuery) { result, error -> + val state = when { + result == null -> Fail(error) + else -> Success(result) + } + + searchResult.postValue(state) + } + } + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/WeatherViewModel.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/WeatherViewModel.kt new file mode 100644 index 0000000..401e2f6 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/models/WeatherViewModel.kt @@ -0,0 +1,36 @@ +package ru.hse.lection05.presentationlayer.models + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import org.koin.core.component.KoinApiExtension +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import ru.hse.lection05.businesslayer.repositories.IWeatherRepository +import ru.hse.lection05.presentationlayer.Fail +import ru.hse.lection05.presentationlayer.Pending +import ru.hse.lection05.presentationlayer.States +import ru.hse.lection05.presentationlayer.Success +import ru.hse.lection05.objects.Place +import ru.hse.lection05.objects.WeatherData + +@KoinApiExtension +class WeatherViewModel: ViewModel(), KoinComponent { + protected val repository by inject() + protected val weatherData = MutableLiveData>() + + + fun weatherData(): LiveData> = weatherData + + fun load(place: Place) { + weatherData.postValue(Pending()) + repository.weather(place.id) { result, error -> + val state = when { + result == null -> Fail(error) + else -> Success(result) + } + + weatherData.postValue(state) + } + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/presenters/PlacePresenter.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/presenters/PlacePresenter.kt new file mode 100644 index 0000000..825703e --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/presenters/PlacePresenter.kt @@ -0,0 +1,28 @@ +package ru.hse.lection05.presentationlayer.presenters + +import android.os.Handler +import android.os.Looper +import ru.hse.lection05.businesslayer.repositories.RepositoryFactory +import ru.hse.lection05.businesslayer.repositories.IPlaceRepository +import ru.hse.lection05.presentationlayer.views.IPlaceView +import java.util.concurrent.TimeUnit + +class PlacePresenter { + protected val handler = Handler(Looper.getMainLooper()) + + protected var view: IPlaceView? = null + + + + fun attachView(view: IPlaceView) { + this.view = view + } + + fun detachView(view: IPlaceView) { + this.view = null + } + + fun startTimer() { + handler.postDelayed( {view?.nextStep()} , TimeUnit.SECONDS.toMillis(1)) + } +} \ No newline at end of file diff --git a/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/views/IPlaceView.kt b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/views/IPlaceView.kt new file mode 100644 index 0000000..5ae4d68 --- /dev/null +++ b/lection05/app/src/main/java/ru/hse/lection05/presentationlayer/views/IPlaceView.kt @@ -0,0 +1,5 @@ +package ru.hse.lection05.presentationlayer.views + +interface IPlaceView { + fun nextStep() +} \ No newline at end of file diff --git a/lection05/app/src/main/res/drawable/ic_add_place.xml b/lection05/app/src/main/res/drawable/ic_add_place.xml new file mode 100644 index 0000000..4279a8d --- /dev/null +++ b/lection05/app/src/main/res/drawable/ic_add_place.xml @@ -0,0 +1,10 @@ + + + diff --git a/lection05/app/src/main/res/layout/activity_main.xml b/lection05/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index d65ed91..0000000 --- a/lection05/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - -