+
+
+
\ 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 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/lection05/app/src/main/res/layout/content_place.xml b/lection05/app/src/main/res/layout/content_place.xml
new file mode 100644
index 0000000..efe232d
--- /dev/null
+++ b/lection05/app/src/main/res/layout/content_place.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection05/app/src/main/res/layout/content_place_add.xml b/lection05/app/src/main/res/layout/content_place_add.xml
new file mode 100644
index 0000000..6ddfc3b
--- /dev/null
+++ b/lection05/app/src/main/res/layout/content_place_add.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection05/app/src/main/res/layout/contetn_places.xml b/lection05/app/src/main/res/layout/contetn_places.xml
new file mode 100644
index 0000000..7d5e7ac
--- /dev/null
+++ b/lection05/app/src/main/res/layout/contetn_places.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection05/app/src/main/res/layout/contetn_splash.xml b/lection05/app/src/main/res/layout/contetn_splash.xml
new file mode 100644
index 0000000..527ca6f
--- /dev/null
+++ b/lection05/app/src/main/res/layout/contetn_splash.xml
@@ -0,0 +1,15 @@
+
+
+
+
\ No newline at end of file
diff --git a/lection05/app/src/main/res/layout/item_suggest_place.xml b/lection05/app/src/main/res/layout/item_suggest_place.xml
new file mode 100644
index 0000000..e5035d6
--- /dev/null
+++ b/lection05/app/src/main/res/layout/item_suggest_place.xml
@@ -0,0 +1,32 @@
+
+
+
+
\ No newline at end of file
diff --git a/lection05/app/src/main/res/mipmap-hdpi/ic_launcher.png b/lection05/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/lection05/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/lection05/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/lection05/app/src/main/res/mipmap-mdpi/ic_launcher.png b/lection05/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/lection05/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/lection05/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/lection05/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/lection05/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/lection05/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/lection05/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/lection05/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/lection05/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/lection05/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/lection05/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/lection05/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection05/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/lection05/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/lection05/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/lection05/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/lection05/app/src/main/res/values/strings.xml b/lection05/app/src/main/res/values/strings.xml
deleted file mode 100644
index e921f81..0000000
--- a/lection05/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Lesson 05
-
\ No newline at end of file
diff --git a/lection05/build.gradle b/lection05/build.gradle
deleted file mode 100644
index 611ef82..0000000
--- a/lection05/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/lection05/gradle/wrapper/gradle-wrapper.jar b/lection05/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index e708b1c..0000000
Binary files a/lection05/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/lection05/settings.gradle b/lection05/settings.gradle
deleted file mode 100644
index f2a20d9..0000000
--- a/lection05/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 = "Lesson 05"
-include ':app'
diff --git a/lection06/.gitignore b/lection06/.gitignore
new file mode 100644
index 0000000..ef26de6
--- /dev/null
+++ b/lection06/.gitignore
@@ -0,0 +1,16 @@
+.idea
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/lection06/app/src/androidTest/java/com/lionzxy/testapplication/ExampleInstrumentedTest.kt b/lection06/app/src/androidTest/java/com/lionzxy/testapplication/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..4bbd4ab
--- /dev/null
+++ b/lection06/app/src/androidTest/java/com/lionzxy/testapplication/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.lionzxy.testapplication
+
+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.lionzxy.testapplication", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/lection06/app/src/main/java/com/lionzxy/testapplication/GithubApi.kt b/lection06/app/src/main/java/com/lionzxy/testapplication/GithubApi.kt
new file mode 100644
index 0000000..bbb61d9
--- /dev/null
+++ b/lection06/app/src/main/java/com/lionzxy/testapplication/GithubApi.kt
@@ -0,0 +1,12 @@
+package com.lionzxy.testapplication
+
+import retrofit2.Call
+import retrofit2.http.GET
+import retrofit2.http.Path
+
+interface GithubApi {
+ @GET("users/{user}/repos")
+ fun getUserRepos(
+ @Path("user") user: String
+ ): Call>
+}
\ No newline at end of file
diff --git a/lection06/app/src/main/java/com/lionzxy/testapplication/GithubRepo.kt b/lection06/app/src/main/java/com/lionzxy/testapplication/GithubRepo.kt
new file mode 100644
index 0000000..f2497d2
--- /dev/null
+++ b/lection06/app/src/main/java/com/lionzxy/testapplication/GithubRepo.kt
@@ -0,0 +1,8 @@
+package com.lionzxy.testapplication
+
+import com.google.gson.annotations.SerializedName
+
+data class GithubRepo(
+ @SerializedName("id")
+ val id: Int
+)
\ No newline at end of file
diff --git a/lection06/app/src/main/java/com/lionzxy/testapplication/MainActivity.kt b/lection06/app/src/main/java/com/lionzxy/testapplication/MainActivity.kt
new file mode 100644
index 0000000..f86eaec
--- /dev/null
+++ b/lection06/app/src/main/java/com/lionzxy/testapplication/MainActivity.kt
@@ -0,0 +1,35 @@
+package com.lionzxy.testapplication
+
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
+import com.lionzxy.testapplication.databinding.ActivityMainBinding
+import com.lionzxy.testapplication.requests.GetGithubRepoRequest
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+class MainActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityMainBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ lifecycleScope.launch {
+ val repo = getRepos()
+ setText(repo)
+ }
+ }
+
+ suspend fun getRepos(): List = withContext(Dispatchers.IO) {
+ GetGithubRepoRequest.getRepos()
+ }
+
+ suspend fun setText(repos: List) = withContext(Dispatchers.Main) {
+ Log.i("MainActivity", "My repos count: ${repos.size}")
+ }
+}
\ No newline at end of file
diff --git a/lection06/app/src/main/java/com/lionzxy/testapplication/MyApplication.kt b/lection06/app/src/main/java/com/lionzxy/testapplication/MyApplication.kt
new file mode 100644
index 0000000..6fd46cb
--- /dev/null
+++ b/lection06/app/src/main/java/com/lionzxy/testapplication/MyApplication.kt
@@ -0,0 +1,10 @@
+package com.lionzxy.testapplication
+
+import android.app.Application
+
+class MyApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+ }
+}
\ No newline at end of file
diff --git a/lection06/app/src/main/java/com/lionzxy/testapplication/requests/GetGithubRepoRequest.kt b/lection06/app/src/main/java/com/lionzxy/testapplication/requests/GetGithubRepoRequest.kt
new file mode 100644
index 0000000..5467905
--- /dev/null
+++ b/lection06/app/src/main/java/com/lionzxy/testapplication/requests/GetGithubRepoRequest.kt
@@ -0,0 +1,39 @@
+package com.lionzxy.testapplication.requests
+
+import com.lionzxy.testapplication.GithubApi
+import com.lionzxy.testapplication.GithubRepo
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import java.lang.ref.WeakReference
+
+class GetGithubRepoRequest : Runnable {
+ private var listener = WeakReference(null)
+
+ companion object {
+ fun getRepos(): List {
+ val retrofit = Retrofit.Builder()
+ .baseUrl("https://api.github.com/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+
+ val githubApi = retrofit.create(GithubApi::class.java)
+ val repos = githubApi.getUserRepos("LionZXY").execute()
+ return repos.body()!!
+ }
+ }
+
+ override fun run() {
+
+
+ listener.get()?.onRepoAccept(getRepos())
+ }
+
+ fun subscribe(inputListener: IResultReciever) {
+ listener = WeakReference(inputListener)
+ }
+
+ fun unsubscribe() {
+ listener.clear()
+ }
+
+}
\ No newline at end of file
diff --git a/lection06/app/src/main/java/com/lionzxy/testapplication/requests/IResultReciever.kt b/lection06/app/src/main/java/com/lionzxy/testapplication/requests/IResultReciever.kt
new file mode 100644
index 0000000..15ca33e
--- /dev/null
+++ b/lection06/app/src/main/java/com/lionzxy/testapplication/requests/IResultReciever.kt
@@ -0,0 +1,7 @@
+package com.lionzxy.testapplication.requests
+
+import com.lionzxy.testapplication.GithubRepo
+
+interface IResultReciever {
+ fun onRepoAccept(list: List)
+}
\ No newline at end of file
diff --git a/lection06/app/src/main/res/layout/activity_main.xml b/lection06/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 6b3825f..0000000
--- a/lection06/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/lection06/app/src/main/res/menu/menu_main.xml b/lection06/app/src/main/res/menu/menu_main.xml
deleted file mode 100644
index ec147aa..0000000
--- a/lection06/app/src/main/res/menu/menu_main.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
\ No newline at end of file
diff --git a/lection06/app/src/main/res/navigation/nav_graph.xml b/lection06/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 0000000..96b02d2
--- /dev/null
+++ b/lection06/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection06/app/src/main/res/values/strings.xml b/lection06/app/src/main/res/values/strings.xml
deleted file mode 100644
index 00b7092..0000000
--- a/lection06/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
- GithubApplication
- Settings
-
- First Fragment
- Second Fragment
- Next
- Previous
-
- Hello first fragment
- Hello second fragment. Arg: %1$s
-
\ No newline at end of file
diff --git a/lection06/app/src/test/java/com/lionzxy/testapplication/ExampleUnitTest.kt b/lection06/app/src/test/java/com/lionzxy/testapplication/ExampleUnitTest.kt
new file mode 100644
index 0000000..cd59ec7
--- /dev/null
+++ b/lection06/app/src/test/java/com/lionzxy/testapplication/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.lionzxy.testapplication
+
+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/lection06/build.gradle b/lection06/build.gradle
deleted file mode 100644
index 9db2bf1..0000000
--- a/lection06/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.31"
-
- // 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/lection06/gradle/wrapper/gradle-wrapper.jar b/lection06/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index e708b1c..0000000
Binary files a/lection06/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/lection06/gradle/wrapper/gradle-wrapper.properties b/lection06/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 109e367..0000000
--- a/lection06/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Wed Oct 20 19:47:35 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
diff --git a/lection06/settings.gradle b/lection06/settings.gradle
deleted file mode 100644
index 9d083d8..0000000
--- a/lection06/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 = "GithubApplication"
-include ':app'
diff --git a/lection08/2021-android-customview-sample/.gitignore b/lection08/2021-android-customview-sample/.gitignore
new file mode 100644
index 0000000..e3b0769
--- /dev/null
+++ b/lection08/2021-android-customview-sample/.gitignore
@@ -0,0 +1,10 @@
+*.iml
+.gradle
+/local.properties
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+/.idea/
diff --git a/lection08/2021-android-customview-sample/LICENSE b/lection08/2021-android-customview-sample/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/lection08/2021-android-customview-sample/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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
+
+ http://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.
diff --git a/lection08/2021-android-customview-sample/README.MD b/lection08/2021-android-customview-sample/README.MD
new file mode 100644
index 0000000..9854a8d
--- /dev/null
+++ b/lection08/2021-android-customview-sample/README.MD
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/.gitignore b/lection08/2021-android-customview-sample/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/lection08/2021-android-customview-sample/app/build.gradle b/lection08/2021-android-customview-sample/app/build.gradle
new file mode 100644
index 0000000..0ff6ec2
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/build.gradle
@@ -0,0 +1,30 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+android {
+ compileSdkVersion 30
+ defaultConfig {
+ applicationId "ru.ok.technopolis.customview"
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation "androidx.core:core-ktx:1.3.2"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+repositories {
+ mavenCentral()
+}
diff --git a/lection08/2021-android-customview-sample/app/proguard-rules.pro b/lection08/2021-android-customview-sample/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/lection08/2021-android-customview-sample/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
diff --git a/lection08/2021-android-customview-sample/app/src/main/AndroidManifest.xml b/lection08/2021-android-customview-sample/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2b25ad3
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/CustomLayout.kt b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/CustomLayout.kt
new file mode 100644
index 0000000..50bb29d
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/CustomLayout.kt
@@ -0,0 +1,37 @@
+package ru.ok.technopolis.customview
+
+import android.content.Context
+import android.util.AttributeSet
+import android.util.Log
+import android.widget.FrameLayout
+import androidx.annotation.AttrRes
+
+class CustomLayout @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ @AttrRes defStyleAttr: Int = 0
+) : FrameLayout(context, attrs, defStyleAttr) {
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ Log.d("!!!","onMeasure")
+
+ val width = MeasureSpec.getSize(widthMeasureSpec)
+ val height = MeasureSpec.getSize(heightMeasureSpec)
+
+ val widthSpec = MeasureSpec.makeMeasureSpec(width / childCount, MeasureSpec.EXACTLY)
+ for (i in 0 until childCount) {
+ getChildAt(i).measure(widthSpec, heightMeasureSpec)
+ }
+
+ setMeasuredDimension(width, height)
+ }
+
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+ Log.d("!!!","onLayout")
+ var currentLeft = 0
+ for (i in 0 until childCount) {
+ getChildAt(i).layout(currentLeft, 0, currentLeft + measuredWidth / childCount, measuredHeight)
+ currentLeft += measuredWidth / childCount
+ }
+ }
+}
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/LinearInterpolation.kt b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/LinearInterpolation.kt
new file mode 100644
index 0000000..14eabb0
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/LinearInterpolation.kt
@@ -0,0 +1,25 @@
+package ru.ok.technopolis.customview
+
+// https://github.com/ajbanks/arff-builder/blob/3fc8f6860a37d33cd93081a9c8c0025fd70872f5/src/stretching/LinearInterpolation.java
+object LinearInterpolation {
+ @JvmStatic
+ fun interpolateArray(source: IntArray, destinationLength: Int): IntArray {
+ val destination = IntArray(destinationLength)
+ destination[0] = source[0]
+ var jPrevious = 0
+ for (i in 1 until source.size) {
+ val j = i * (destination.size - 1) / (source.size - 1)
+ interpolate(destination, jPrevious, j, source[i - 1].toDouble(), source[i].toDouble())
+ jPrevious = j
+ }
+ return destination
+ }
+
+ private fun interpolate(destination: IntArray, destFrom: Int, destTo: Int, valueFrom: Double, valueTo: Double) {
+ val destLength = destTo - destFrom
+ val valueLength = valueTo - valueFrom
+ for (i in 0..destLength) {
+ destination[destFrom + i] = (valueFrom + valueLength * i / destLength).toInt()
+ }
+ }
+}
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/MainActivity.kt b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/MainActivity.kt
new file mode 100644
index 0000000..f0081f2
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/MainActivity.kt
@@ -0,0 +1,11 @@
+package ru.ok.technopolis.customview
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+
+class MainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ }
+}
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/WaveRepository.kt b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/WaveRepository.kt
new file mode 100644
index 0000000..2e7265d
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/WaveRepository.kt
@@ -0,0 +1,21 @@
+package ru.ok.technopolis.customview
+
+import java.util.*
+
+object WaveRepository {
+
+ const val MAX_VOLUME = 100
+ private const val WAVE_LENGTH = 200
+
+ @JvmStatic
+ val waveData: IntArray
+ get() {
+ val data = IntArray(WAVE_LENGTH)
+ val r = Random()
+ for (i in data.indices) {
+ val value = r.nextInt(MAX_VOLUME + 1)
+ data[i] = value
+ }
+ return data
+ }
+}
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/WaveView.kt b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/WaveView.kt
new file mode 100644
index 0000000..f9aea90
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/java/ru/ok/technopolis/customview/WaveView.kt
@@ -0,0 +1,77 @@
+package ru.ok.technopolis.customview
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.util.AttributeSet
+import android.util.Log
+import android.util.TypedValue
+import android.view.View
+import ru.ok.technopolis.customview.LinearInterpolation.interpolateArray
+import ru.ok.technopolis.customview.WaveRepository.waveData
+
+class WaveView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : View(context, attrs, defStyleAttr) {
+
+ private val wavePath = Path()
+ private val linePaint = Paint()
+ private val itemWidth: Int
+ private val originalData: IntArray
+ private var measuredData: IntArray? = null
+
+ companion object {
+ private const val DEFAULT_ITEM_WIDTH_DP = 2
+ private const val DEFAULT_ITEM_COLOR = Color.BLACK
+ }
+
+ init {
+ val displayMetrics = context.resources.displayMetrics
+ var itemWidthFromAttr = (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_ITEM_WIDTH_DP.toFloat(), displayMetrics) + 0.5f).toInt()
+ var itemColorFromAttr = DEFAULT_ITEM_COLOR
+
+ if (attrs != null) {
+ val typedArray = context.obtainStyledAttributes(attrs, R.styleable.WaveView)
+ itemWidthFromAttr = typedArray.getDimensionPixelSize(R.styleable.WaveView_itemWidth, itemWidthFromAttr)
+ itemColorFromAttr = typedArray.getColor(R.styleable.WaveView_itemColor, itemColorFromAttr)
+ typedArray.recycle()
+ }
+
+ itemWidth = itemWidthFromAttr
+ originalData = waveData
+ linePaint.style = Paint.Style.STROKE
+ linePaint.color = itemColorFromAttr
+ linePaint.strokeWidth = itemWidthFromAttr.toFloat()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val width = MeasureSpec.getSize(widthMeasureSpec)
+ val height = MeasureSpec.getSize(heightMeasureSpec)
+
+ val itemCount = (width - paddingStart - paddingEnd + itemWidth) / (itemWidth * 2)
+ measuredData = interpolateArray(originalData, itemCount)
+
+ setMeasuredDimension(width, height)
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ val measuredData = measuredData ?: return
+
+ wavePath.reset()
+ val measuredHeight = measuredHeight - paddingTop - paddingBottom
+ var currentX = paddingStart
+ for (data in measuredData) {
+ val height = data.toFloat() / WaveRepository.MAX_VOLUME * measuredHeight
+ val startY = measuredHeight.toFloat() / 2f - height / 2f + paddingTop
+ val endY = startY + height
+ wavePath.moveTo(currentX.toFloat(), startY)
+ wavePath.lineTo(currentX.toFloat(), endY)
+ currentX += itemWidth * 2
+ }
+ canvas.drawPath(wavePath, linePaint)
+ }
+}
\ No newline at end of file
diff --git a/lection03/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/lection08/2021-android-customview-sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
similarity index 100%
rename from lection03/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
rename to lection08/2021-android-customview-sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/drawable/ic_launcher_background.xml b/lection08/2021-android-customview-sample/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/layout/activity_main.xml b/lection08/2021-android-customview-sample/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..b9331d0
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
Binary files /dev/null and b/lection08/2021-android-customview-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/values/attrs.xml b/lection08/2021-android-customview-sample/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..006b11d
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/values/attrs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/values/colors.xml b/lection08/2021-android-customview-sample/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..8ed6936
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
+ #D50000
+ #00C853
+ #01579B
+
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/values/strings.xml b/lection08/2021-android-customview-sample/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9fb4bf5
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ WaveView
+
diff --git a/lection08/2021-android-customview-sample/app/src/main/res/values/styles.xml b/lection08/2021-android-customview-sample/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/lection08/2021-android-customview-sample/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/lection08/2021-android-customview-sample/build.gradle b/lection08/2021-android-customview-sample/build.gradle
new file mode 100644
index 0000000..f387b2b
--- /dev/null
+++ b/lection08/2021-android-customview-sample/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+ ext.kotlin_version = '1.4.32'
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:4.2.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/lection08/2021-android-customview-sample/docs/image.png b/lection08/2021-android-customview-sample/docs/image.png
new file mode 100644
index 0000000..eb20cbc
Binary files /dev/null and b/lection08/2021-android-customview-sample/docs/image.png differ
diff --git a/lection08/2021-android-customview-sample/gradle.properties b/lection08/2021-android-customview-sample/gradle.properties
new file mode 100644
index 0000000..d546dea
--- /dev/null
+++ b/lection08/2021-android-customview-sample/gradle.properties
@@ -0,0 +1,17 @@
+# 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.
+android.enableJetifier=true
+android.useAndroidX=true
+org.gradle.jvmargs=-Xmx1536m
+# 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
+
+
diff --git a/lection08/2021-android-customview-sample/gradle/wrapper/gradle-wrapper.jar b/lection08/2021-android-customview-sample/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/lection08/2021-android-customview-sample/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lection03/gradle/wrapper/gradle-wrapper.properties b/lection08/2021-android-customview-sample/gradle/wrapper/gradle-wrapper.properties
similarity index 80%
rename from lection03/gradle/wrapper/gradle-wrapper.properties
rename to lection08/2021-android-customview-sample/gradle/wrapper/gradle-wrapper.properties
index ca53886..e0b9da1 100644
--- a/lection03/gradle/wrapper/gradle-wrapper.properties
+++ b/lection08/2021-android-customview-sample/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Sep 29 18:13:37 MSK 2021
+#Tue Apr 06 16:19:45 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.7.1-all.zip
diff --git a/lection05/gradlew b/lection08/2021-android-customview-sample/gradlew
old mode 100644
new mode 100755
similarity index 75%
rename from lection05/gradlew
rename to lection08/2021-android-customview-sample/gradlew
index 4f906e0..cccdd3d
--- a/lection05/gradlew
+++ b/lection08/2021-android-customview-sample/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/lection02/gradlew.bat b/lection08/2021-android-customview-sample/gradlew.bat
similarity index 66%
rename from lection02/gradlew.bat
rename to lection08/2021-android-customview-sample/gradlew.bat
index 107acd3..f955316 100644
--- a/lection02/gradlew.bat
+++ b/lection08/2021-android-customview-sample/gradlew.bat
@@ -1,19 +1,3 @@
-@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
@@ -29,18 +13,15 @@ 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"
+set DEFAULT_JVM_OPTS=
@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
+if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +35,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto execute
+if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,14 +45,28 @@ echo location of your Java installation.
goto fail
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
: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 %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
diff --git a/lection08/2021-android-customview-sample/settings.gradle b/lection08/2021-android-customview-sample/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/lection08/2021-android-customview-sample/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/lection08/2021-android-rv-swipe-sample/.gitignore b/lection08/2021-android-rv-swipe-sample/.gitignore
new file mode 100644
index 0000000..a99282a
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/.gitignore
@@ -0,0 +1,10 @@
+*.iml
+.gradle
+/local.properties
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+/.idea/
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/README.MD b/lection08/2021-android-rv-swipe-sample/README.MD
new file mode 100644
index 0000000..321d484
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/README.MD
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/.gitignore b/lection08/2021-android-rv-swipe-sample/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/lection08/2021-android-rv-swipe-sample/app/build.gradle b/lection08/2021-android-rv-swipe-sample/app/build.gradle
new file mode 100644
index 0000000..f9d37b6
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+android {
+ compileSdkVersion 30
+ defaultConfig {
+ applicationId "ru.ok.technopolis.animations"
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
+ implementation 'androidx.recyclerview:recyclerview:1.2.0'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation "androidx.core:core-ktx:1.3.2"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+repositories {
+ mavenCentral()
+}
diff --git a/lection08/2021-android-rv-swipe-sample/app/proguard-rules.pro b/lection08/2021-android-rv-swipe-sample/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/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
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/AndroidManifest.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6082d88
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/ItemSwipeManger.kt b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/ItemSwipeManger.kt
new file mode 100644
index 0000000..6a3ad46
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/ItemSwipeManger.kt
@@ -0,0 +1,151 @@
+package ru.ok.technopolis.animations
+
+import android.content.Context
+import android.view.MotionEvent
+import android.view.VelocityTracker
+import android.view.View
+import android.view.ViewConfiguration
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.FlingAnimation
+import androidx.dynamicanimation.animation.SpringAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.*
+import java.util.*
+
+class ItemSwipeManger(
+ context: Context,
+ private val listener: SwipeListener,
+) : OnItemTouchListener, OnChildAttachStateChangeListener {
+
+ private val animations: MutableMap> = HashMap()
+ private val touchSlop: Int = ViewConfiguration.get(context).scaledTouchSlop
+ private var initialTouchX = 0f
+ private var recyclerView: RecyclerView? = null
+ private var velocityTracker: VelocityTracker? = null
+ private var swipedChild: View? = null
+
+ fun attachToRecyclerView(recyclerView: RecyclerView) {
+ this.recyclerView = recyclerView
+
+ recyclerView.addOnItemTouchListener(this)
+ recyclerView.addOnChildAttachStateChangeListener(this)
+ }
+
+ fun detachFromRecyclerView() {
+ val recyclerView = recyclerView ?: return
+
+ recyclerView.removeOnItemTouchListener(this)
+ recyclerView.removeOnChildAttachStateChangeListener(this)
+ for (animation in animations.values) {
+ animation.cancel()
+ }
+ animations.clear()
+ }
+
+ override fun onChildViewAttachedToWindow(view: View) {
+ }
+
+ override fun onChildViewDetachedFromWindow(view: View) {
+ val recyclerView = recyclerView ?: return
+
+ view.translationX = 0f
+ recyclerView.getChildViewHolder(view)?.also { animations.remove(it) }
+ }
+
+ override fun onInterceptTouchEvent(rv: RecyclerView, event: MotionEvent): Boolean {
+ when (event.actionMasked) {
+ MotionEvent.ACTION_DOWN -> {
+ initialTouchX = event.x
+
+ velocityTracker?.recycle()
+ velocityTracker = VelocityTracker.obtain().apply { addMovement(event) }
+
+ return false
+ }
+ MotionEvent.ACTION_MOVE -> {
+ velocityTracker?.addMovement(event)
+
+ val dragged = event.x - initialTouchX > touchSlop
+ if (dragged) {
+ swipedChild = rv.findChildViewUnder(event.x, event.y)
+ }
+
+ return dragged
+ }
+ }
+ return false
+ }
+
+ override fun onTouchEvent(rv: RecyclerView, event: MotionEvent) {
+ val swipedChild = swipedChild ?: return
+ val velocityTracker = velocityTracker ?: return
+
+ velocityTracker.addMovement(event)
+ when (event.actionMasked) {
+ MotionEvent.ACTION_MOVE -> swipedChild.translationX = event.x - initialTouchX
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+ val swipeViewHolder = rv.findContainingViewHolder(swipedChild) ?: return
+ velocityTracker.computeCurrentVelocity(1000)
+ val velocity = velocityTracker.xVelocity
+ if (velocity > 0) {
+ animateWithFling(swipeViewHolder, velocity)
+ } else {
+ animateWithSpring(swipeViewHolder, velocity)
+ }
+ velocityTracker.clear()
+ }
+ }
+ }
+
+ override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
+ }
+
+ private fun animateWithFling(viewHolder: ViewHolder, velocity: Float) {
+ val recyclerView = recyclerView ?: return
+
+ val animation = FlingAnimation(swipedChild, DynamicAnimation.TRANSLATION_X)
+ animation.friction = 1f
+ animation.setStartVelocity(velocity)
+ animation.setMaxValue(viewHolder.itemView.width.toFloat())
+
+ viewHolder.setIsRecyclable(false)
+
+ animation.addEndListener { _, _, value, velocity ->
+ if (value >= recyclerView.width) {
+ viewHolder.setIsRecyclable(true)
+ listener.onSwiped(viewHolder)
+ } else {
+ animateWithSpring(viewHolder, velocity)
+ }
+ }
+
+ animations[viewHolder] = animation
+ animation.start()
+ }
+
+ private fun animateWithSpring(viewHolder: ViewHolder, velocity: Float) {
+ val animation = SpringAnimation(viewHolder.itemView, DynamicAnimation.TRANSLATION_X)
+ animation.setStartVelocity(velocity)
+
+ val springForce = SpringForce(0F)
+ springForce.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY
+ springForce.stiffness = SpringForce.STIFFNESS_LOW
+ animation.spring = springForce
+
+ viewHolder.setIsRecyclable(false)
+
+ animation.addEndListener { _, _, _, _ ->
+ animations.remove(viewHolder)
+ viewHolder.setIsRecyclable(true)
+ }
+
+ animations[viewHolder] = animation
+ animation.start()
+ }
+
+ interface SwipeListener {
+ fun onSwiped(viewHolder: ViewHolder)
+ }
+
+}
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/MainActivity.kt b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/MainActivity.kt
new file mode 100644
index 0000000..4769b1e
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/MainActivity.kt
@@ -0,0 +1,83 @@
+package ru.ok.technopolis.animations
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+class MainActivity : AppCompatActivity(), ItemSwipeManger.SwipeListener {
+
+ private val movies = generateMovieList().toMutableList()
+ private val moviesAdapter = MoviesAdapter(movies)
+
+ private lateinit var recyclerView: RecyclerView
+ private lateinit var itemSwipeManger: ItemSwipeManger
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ recyclerView = findViewById(R.id.activity_main__rv_movies)
+ recyclerView.adapter = moviesAdapter
+ recyclerView.layoutManager = LinearLayoutManager(this)
+
+ itemSwipeManger = ItemSwipeManger(this, this)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ itemSwipeManger.attachToRecyclerView(recyclerView)
+ }
+
+ override fun onStop() {
+ itemSwipeManger.detachFromRecyclerView()
+ super.onStop()
+ }
+
+ override fun onSwiped(viewHolder: RecyclerView.ViewHolder) {
+ val position = viewHolder.adapterPosition
+ if (position != RecyclerView.NO_POSITION) {
+ moviesAdapter.removeItem(position)
+ }
+ }
+}
+
+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/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/Movie.kt b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/Movie.kt
new file mode 100644
index 0000000..856e90a
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/Movie.kt
@@ -0,0 +1,3 @@
+package ru.ok.technopolis.animations
+
+data class Movie(val name: String, val description: String, val poster: Int)
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/MoviesAdapter.kt b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/MoviesAdapter.kt
new file mode 100644
index 0000000..ffc4d63
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/java/ru/ok/technopolis/animations/MoviesAdapter.kt
@@ -0,0 +1,48 @@
+package ru.ok.technopolis.animations
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
+import ru.ok.technopolis.animations.MoviesAdapter.MovieViewHolder
+
+class MoviesAdapter(private val movies: MutableList) : RecyclerView.Adapter() {
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): MovieViewHolder {
+ val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.movie_item, viewGroup, false)
+ return MovieViewHolder(view)
+ }
+
+ override fun onBindViewHolder(viewHolder: MovieViewHolder, i: Int) {
+ val movie = movies[i]
+ viewHolder.bind(movie)
+ viewHolder.itemView.tag = movie
+ }
+
+ override fun getItemCount(): Int {
+ return movies.size
+ }
+
+ fun removeItem(position: Int) {
+ movies.removeAt(position)
+ notifyItemRemoved(position)
+ }
+
+ class MovieViewHolder(itemView: View) : ViewHolder(itemView) {
+
+ private val nameTextView: TextView = itemView.findViewById(R.id.movie_item__tv_name)
+ private val descriptionTextView: TextView = itemView.findViewById(R.id.movie_item__tv_description)
+ private val posterImageView: ImageView = itemView.findViewById(R.id.movie_item__iv_poster)
+
+ fun bind(movie: Movie) {
+ nameTextView.text = movie.name
+ descriptionTextView.text = movie.description
+ posterImageView.setImageResource(movie.poster)
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_1.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_1.png
new file mode 100755
index 0000000..106a031
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_1.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_2.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_2.png
new file mode 100755
index 0000000..b93365e
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_2.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_3.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_3.png
new file mode 100755
index 0000000..aa9bf6a
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_3.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_4.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_4.png
new file mode 100755
index 0000000..afcff88
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_4.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_5.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_5.png
new file mode 100755
index 0000000..7541f5c
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_5.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_6.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_6.png
new file mode 100755
index 0000000..12c3452
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_6.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_7.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_7.png
new file mode 100755
index 0000000..94171cf
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-hdpi/movie_7.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_1.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_1.png
new file mode 100755
index 0000000..dae8e7e
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_1.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_2.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_2.png
new file mode 100755
index 0000000..87fe93b
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_2.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_3.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_3.png
new file mode 100755
index 0000000..d9afa44
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_3.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_4.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_4.png
new file mode 100755
index 0000000..af94f73
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_4.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_5.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_5.png
new file mode 100755
index 0000000..90cef94
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_5.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_6.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_6.png
new file mode 100755
index 0000000..62da4ea
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_6.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_7.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_7.png
new file mode 100755
index 0000000..8e601d9
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-ldpi/movie_7.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_1.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_1.png
new file mode 100755
index 0000000..9763aeb
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_1.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_2.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_2.png
new file mode 100755
index 0000000..e72b6dc
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_2.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_3.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_3.png
new file mode 100755
index 0000000..2f15fb9
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_3.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_4.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_4.png
new file mode 100755
index 0000000..7a8cd92
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_4.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_5.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_5.png
new file mode 100755
index 0000000..4a0bfae
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_5.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_6.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_6.png
new file mode 100755
index 0000000..d23a801
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_6.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_7.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_7.png
new file mode 100755
index 0000000..830afeb
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-mdpi/movie_7.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_1.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_1.png
new file mode 100755
index 0000000..59afb66
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_1.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_2.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_2.png
new file mode 100755
index 0000000..89088d5
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_2.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_3.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_3.png
new file mode 100755
index 0000000..97aca7d
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_3.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_4.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_4.png
new file mode 100755
index 0000000..d85fcd7
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_4.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_5.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_5.png
new file mode 100755
index 0000000..27c9de2
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_5.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_6.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_6.png
new file mode 100755
index 0000000..fd9c277
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_6.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_7.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_7.png
new file mode 100755
index 0000000..88cc321
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xhdpi/movie_7.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_1.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_1.png
new file mode 100755
index 0000000..47f758d
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_1.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_2.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_2.png
new file mode 100755
index 0000000..0188d5e
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_2.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_3.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_3.png
new file mode 100755
index 0000000..1c94edf
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_3.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_4.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_4.png
new file mode 100755
index 0000000..cfbe346
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_4.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_5.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_5.png
new file mode 100755
index 0000000..4bb4915
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_5.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_6.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_6.png
new file mode 100755
index 0000000..8ed7d30
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_6.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_7.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_7.png
new file mode 100755
index 0000000..43bf92c
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxhdpi/movie_7.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_1.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_1.png
new file mode 100755
index 0000000..5b46e33
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_1.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_2.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_2.png
new file mode 100755
index 0000000..c103544
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_2.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_3.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_3.png
new file mode 100755
index 0000000..b7cbf3f
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_3.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_4.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_4.png
new file mode 100755
index 0000000..eb94bd4
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_4.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_5.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_5.png
new file mode 100755
index 0000000..52ed058
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_5.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_6.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_6.png
new file mode 100755
index 0000000..be3124f
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_6.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_7.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_7.png
new file mode 100755
index 0000000..e54b995
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable-xxxhdpi/movie_7.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable/circle.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable/circle.xml
new file mode 100644
index 0000000..828e182
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable/circle.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable/ic_launcher_background.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/layout/activity_main.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..103b58f
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/layout/movie_item.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/layout/movie_item.xml
new file mode 100644
index 0000000..6f558b5
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/layout/movie_item.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/colors.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..69b2233
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/strings.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c9be55c
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Animations
+
diff --git a/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/styles.xml b/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/lection03/build.gradle b/lection08/2021-android-rv-swipe-sample/build.gradle
similarity index 60%
rename from lection03/build.gradle
rename to lection08/2021-android-rv-swipe-sample/build.gradle
index 9db2bf1..43754d6 100644
--- a/lection03/build.gradle
+++ b/lection08/2021-android-rv-swipe-sample/build.gradle
@@ -1,18 +1,29 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
buildscript {
+ ext.kotlin_version = '1.4.32'
repositories {
google()
mavenCentral()
+
}
dependencies {
- classpath "com.android.tools.build:gradle:7.0.2"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
+ classpath 'com.android.tools.build:gradle:4.2.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+
+ }
+}
+
task clean(type: Delete) {
delete rootProject.buildDir
-}
\ No newline at end of file
+}
diff --git a/lection08/2021-android-rv-swipe-sample/docs/image.png b/lection08/2021-android-rv-swipe-sample/docs/image.png
new file mode 100644
index 0000000..29d49f9
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/docs/image.png differ
diff --git a/lection08/2021-android-rv-swipe-sample/gradle.properties b/lection08/2021-android-rv-swipe-sample/gradle.properties
new file mode 100644
index 0000000..d546dea
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/gradle.properties
@@ -0,0 +1,17 @@
+# 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.
+android.enableJetifier=true
+android.useAndroidX=true
+org.gradle.jvmargs=-Xmx1536m
+# 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
+
+
diff --git a/lection08/2021-android-rv-swipe-sample/gradle/wrapper/gradle-wrapper.jar b/lection08/2021-android-rv-swipe-sample/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/lection08/2021-android-rv-swipe-sample/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lection05/gradle/wrapper/gradle-wrapper.properties b/lection08/2021-android-rv-swipe-sample/gradle/wrapper/gradle-wrapper.properties
similarity index 80%
rename from lection05/gradle/wrapper/gradle-wrapper.properties
rename to lection08/2021-android-rv-swipe-sample/gradle/wrapper/gradle-wrapper.properties
index bc38cce..36921e0 100644
--- a/lection05/gradle/wrapper/gradle-wrapper.properties
+++ b/lection08/2021-android-rv-swipe-sample/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Oct 08 18:26:20 MSK 2021
+#Tue Apr 06 17:04:48 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.7.1-all.zip
diff --git a/lection03/gradlew b/lection08/2021-android-rv-swipe-sample/gradlew
similarity index 75%
rename from lection03/gradlew
rename to lection08/2021-android-rv-swipe-sample/gradlew
index 4f906e0..cccdd3d 100755
--- a/lection03/gradlew
+++ b/lection08/2021-android-rv-swipe-sample/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/lection06/gradlew.bat b/lection08/2021-android-rv-swipe-sample/gradlew.bat
similarity index 66%
rename from lection06/gradlew.bat
rename to lection08/2021-android-rv-swipe-sample/gradlew.bat
index 107acd3..f955316 100644
--- a/lection06/gradlew.bat
+++ b/lection08/2021-android-rv-swipe-sample/gradlew.bat
@@ -1,19 +1,3 @@
-@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
@@ -29,18 +13,15 @@ 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"
+set DEFAULT_JVM_OPTS=
@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
+if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +35,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto execute
+if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,14 +45,28 @@ echo location of your Java installation.
goto fail
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
: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 %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
diff --git a/lection08/2021-android-rv-swipe-sample/settings.gradle b/lection08/2021-android-rv-swipe-sample/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/lection08/2021-android-rv-swipe-sample/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/lection08/lesson8/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection08/lesson8/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 2c18de9..1abf3e6 100644
Binary files a/lection08/lesson8/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/lection08/lesson8/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/lection09/app/.gitignore b/lection09/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/lection09/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/lection03/app/build.gradle b/lection09/app/build.gradle
similarity index 63%
rename from lection03/app/build.gradle
rename to lection09/app/build.gradle
index 1882dd3..c27742a 100644
--- a/lection03/app/build.gradle
+++ b/lection09/app/build.gradle
@@ -4,12 +4,13 @@ plugins {
}
android {
- compileSdk 31
+ compileSdk 30
+ buildToolsVersion "30.0.3"
defaultConfig {
- applicationId "com.otopba.hello_world"
+ applicationId "com.lionzxy.lection09"
minSdk 21
- targetSdk 31
+ targetSdk 30
versionCode 1
versionName "1.0"
@@ -33,11 +34,11 @@ android {
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.recyclerview:recyclerview:1.2.1'
+ implementation 'androidx.core:core-ktx:1.3.2'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'com.google.android.material:material:1.2.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ 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/lection09/app/proguard-rules.pro b/lection09/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/lection09/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/lection09/app/src/androidTest/java/com/lionzxy/lection09/ExampleInstrumentedTest.kt b/lection09/app/src/androidTest/java/com/lionzxy/lection09/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..5f9d127
--- /dev/null
+++ b/lection09/app/src/androidTest/java/com/lionzxy/lection09/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.lionzxy.lection09
+
+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.lionzxy.lection09", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/lection03/app/src/main/AndroidManifest.xml b/lection09/app/src/main/AndroidManifest.xml
similarity index 88%
rename from lection03/app/src/main/AndroidManifest.xml
rename to lection09/app/src/main/AndroidManifest.xml
index 402ad51..b366378 100644
--- a/lection03/app/src/main/AndroidManifest.xml
+++ b/lection09/app/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
+ package="com.lionzxy.lection09">
-
+ android:theme="@style/Theme.Lection09">
+
-
\ No newline at end of file
diff --git a/lection09/app/src/main/java/com/lionzxy/lection09/MainActivity.kt b/lection09/app/src/main/java/com/lionzxy/lection09/MainActivity.kt
new file mode 100644
index 0000000..a71393f
--- /dev/null
+++ b/lection09/app/src/main/java/com/lionzxy/lection09/MainActivity.kt
@@ -0,0 +1,11 @@
+package com.lionzxy.lection09
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+
+class MainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ }
+}
\ No newline at end of file
diff --git a/lection09/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/lection09/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/lection09/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/app/src/main/res/drawable/ic_launcher_background.xml b/lection09/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/lection09/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lection09/app/src/main/res/layout/activity_main.xml b/lection09/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..4fc2444
--- /dev/null
+++ b/lection09/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/lection09/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection09/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/lection09/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection09/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/lection09/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/lection09/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/lection09/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/lection09/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/lection09/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/lection09/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/lection09/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/lection09/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/lection09/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/lection09/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/lection09/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/lection09/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/lection09/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/lection09/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/lection09/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/lection09/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/lection09/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/lection09/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/lection09/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/lection09/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/lection02/app/src/main/res/values-night/themes.xml b/lection09/app/src/main/res/values-night/themes.xml
similarity index 88%
rename from lection02/app/src/main/res/values-night/themes.xml
rename to lection09/app/src/main/res/values-night/themes.xml
index 2e270f7..4f95878 100644
--- a/lection02/app/src/main/res/values-night/themes.xml
+++ b/lection09/app/src/main/res/values-night/themes.xml
@@ -1,6 +1,6 @@
-
-
-
+
-
+
\ No newline at end of file
diff --git a/lection09/debugging/src/test/java/com/lionzxy/debugging/ExampleUnitTest.kt b/lection09/debugging/src/test/java/com/lionzxy/debugging/ExampleUnitTest.kt
new file mode 100644
index 0000000..28ad6b9
--- /dev/null
+++ b/lection09/debugging/src/test/java/com/lionzxy/debugging/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.lionzxy.debugging
+
+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/lesson9/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection09/lesson9/src/main/res/mipmap-xxxhdpi/ic_launcher.png
old mode 100755
new mode 100644
index 2c18de9..1abf3e6
Binary files a/lection09/lesson9/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/lection09/lesson9/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/lection09/settings.gradle b/lection09/settings.gradle
deleted file mode 100644
index 7cbaa3e..0000000
--- a/lection09/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-rootProject.name = "Lection9"
-include ':lesson9'
diff --git a/lection09/testapplication/.gitignore b/lection09/testapplication/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/lection09/testapplication/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/lection02/app/build.gradle b/lection09/testapplication/build.gradle
similarity index 59%
rename from lection02/app/build.gradle
rename to lection09/testapplication/build.gradle
index 9d061b1..db5bdda 100644
--- a/lection02/app/build.gradle
+++ b/lection09/testapplication/build.gradle
@@ -4,12 +4,13 @@ plugins {
}
android {
- compileSdk 31
+ compileSdkVersion 30
+ buildToolsVersion "30.0.3"
defaultConfig {
- applicationId "ru.mail.education.lesson02"
- minSdk 21
- targetSdk 31
+ applicationId "com.lionzxy.testapplication"
+ minSdkVersion 16
+ targetSdkVersion 30
versionCode 1
versionName "1.0"
@@ -29,20 +30,16 @@ android {
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.0'
- implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
- implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'androidx.core:core-ktx:1.3.1'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'com.google.android.material:material:1.2.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.+'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ 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/lection09/testapplication/proguard-rules.pro b/lection09/testapplication/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/lection09/testapplication/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/lection09/testapplication/src/androidTest/java/com/lionzxy/testapplication/ExampleInstrumentedTest.kt b/lection09/testapplication/src/androidTest/java/com/lionzxy/testapplication/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..4bbd4ab
--- /dev/null
+++ b/lection09/testapplication/src/androidTest/java/com/lionzxy/testapplication/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.lionzxy.testapplication
+
+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.lionzxy.testapplication", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/lection09/testapplication/src/main/AndroidManifest.xml b/lection09/testapplication/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7acdeca
--- /dev/null
+++ b/lection09/testapplication/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/testapplication/src/main/java/com/lionzxy/testapplication/MainActivity.kt b/lection09/testapplication/src/main/java/com/lionzxy/testapplication/MainActivity.kt
new file mode 100644
index 0000000..a4e4fd1
--- /dev/null
+++ b/lection09/testapplication/src/main/java/com/lionzxy/testapplication/MainActivity.kt
@@ -0,0 +1,11 @@
+package com.lionzxy.testapplication
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+
+class MainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ }
+}
\ No newline at end of file
diff --git a/lection09/testapplication/src/main/res/drawable-v24/ic_launcher_foreground.xml b/lection09/testapplication/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/lection09/testapplication/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/testapplication/src/main/res/drawable/ic_launcher_background.xml b/lection09/testapplication/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/lection09/testapplication/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lection09/testapplication/src/main/res/layout/activity_main.xml b/lection09/testapplication/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..4fc2444
--- /dev/null
+++ b/lection09/testapplication/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/testapplication/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/lection09/testapplication/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection09/testapplication/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/testapplication/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/lection09/testapplication/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/lection09/testapplication/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lection09/testapplication/src/main/res/mipmap-hdpi/ic_launcher.png b/lection09/testapplication/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-hdpi/ic_launcher_round.png b/lection09/testapplication/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-mdpi/ic_launcher.png b/lection09/testapplication/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-mdpi/ic_launcher_round.png b/lection09/testapplication/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-xhdpi/ic_launcher.png b/lection09/testapplication/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/lection09/testapplication/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png b/lection09/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/lection09/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/lection09/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/lection09/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/lection09/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/lection09/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/lection03/app/src/main/res/values-night/themes.xml b/lection09/testapplication/src/main/res/values-night/themes.xml
similarity index 88%
rename from lection03/app/src/main/res/values-night/themes.xml
rename to lection09/testapplication/src/main/res/values-night/themes.xml
index db1d410..4f95878 100644
--- a/lection03/app/src/main/res/values-night/themes.xml
+++ b/lection09/testapplication/src/main/res/values-night/themes.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/lection10/app/src/main/res/values/colors.xml b/lection10/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/lection10/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/lection10/app/src/main/res/values/dimens.xml b/lection10/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..ef95257
--- /dev/null
+++ b/lection10/app/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 16dp
+ 16dp
+ 16dp
+
\ No newline at end of file
diff --git a/lection10/app/src/main/res/values/strings.xml b/lection10/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..dddd05c
--- /dev/null
+++ b/lection10/app/src/main/res/values/strings.xml
@@ -0,0 +1,6 @@
+
+ Lection10
+ Home
+ Dashboard
+ Notifications
+
\ No newline at end of file
diff --git a/lection06/app/src/main/res/values/themes.xml b/lection10/app/src/main/res/values/themes.xml
similarity index 61%
rename from lection06/app/src/main/res/values/themes.xml
rename to lection10/app/src/main/res/values/themes.xml
index 4ffa1cd..509f1a1 100644
--- a/lection06/app/src/main/res/values/themes.xml
+++ b/lection10/app/src/main/res/values/themes.xml
@@ -1,6 +1,6 @@
-
-
-
-
-
+ #ffffff
+ @drawable/ic_launcher_foreground
+ #ff0000
+
\ No newline at end of file
diff --git a/lection10/app/src/test/java/ru/hse/lection10/ExampleUnitTest.kt b/lection10/app/src/test/java/ru/hse/lection10/ExampleUnitTest.kt
new file mode 100644
index 0000000..f3561b1
--- /dev/null
+++ b/lection10/app/src/test/java/ru/hse/lection10/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package ru.hse.lection10
+
+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/lection10/build.gradle b/lection10/build.gradle
new file mode 100644
index 0000000..7674942
--- /dev/null
+++ b/lection10/build.gradle
@@ -0,0 +1,35 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ ext.kotlin_version = "1.5.0"
+ ext.nav_version = "2.3.0"
+ ext.paging_version = "3.0.0"
+ ext.room_version = "2.3.0"
+ ext.hilt_version = "2.35"
+ ext.glide_version ="4.12.0"
+
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.2.1"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
+ classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ jcenter() // Warning: this repository is going to shut down soon
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/lection09/gradle.properties b/lection10/gradle.properties
similarity index 100%
rename from lection09/gradle.properties
rename to lection10/gradle.properties
diff --git a/lection10/gradle/wrapper/gradle-wrapper.jar b/lection10/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/lection10/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lection09/gradle/wrapper/gradle-wrapper.properties b/lection10/gradle/wrapper/gradle-wrapper.properties
similarity index 87%
rename from lection09/gradle/wrapper/gradle-wrapper.properties
rename to lection10/gradle/wrapper/gradle-wrapper.properties
index 4899317..bd2ce3c 100644
--- a/lection09/gradle/wrapper/gradle-wrapper.properties
+++ b/lection10/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,4 @@
-#Fri Nov 05 01:00:22 MSK 2021
+#Wed May 26 18:48:05 MSK 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionPath=wrapper/dists
diff --git a/lection06/gradlew b/lection10/gradlew
old mode 100755
new mode 100644
similarity index 75%
rename from lection06/gradlew
rename to lection10/gradlew
index 4f906e0..cccdd3d
--- a/lection06/gradlew
+++ b/lection10/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/lection05/gradlew.bat b/lection10/gradlew.bat
similarity index 66%
rename from lection05/gradlew.bat
rename to lection10/gradlew.bat
index 107acd3..f955316 100644
--- a/lection05/gradlew.bat
+++ b/lection10/gradlew.bat
@@ -1,19 +1,3 @@
-@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
@@ -29,18 +13,15 @@ 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"
+set DEFAULT_JVM_OPTS=
@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
+if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +35,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto execute
+if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,14 +45,28 @@ echo location of your Java installation.
goto fail
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
: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 %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
diff --git a/lection10/settings.gradle b/lection10/settings.gradle
new file mode 100644
index 0000000..f7f7d8f
--- /dev/null
+++ b/lection10/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = "Lection10"
+include ':app'
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 01 - \320\222\321\201\321\202\321\203\320\277\320\273\320\265\320\275\320\270\320\265.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 01 - \320\222\321\201\321\202\321\203\320\277\320\273\320\265\320\275\320\270\320\265.pdf"
new file mode 100644
index 0000000..c99d388
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 01 - \320\222\321\201\321\202\321\203\320\277\320\273\320\265\320\275\320\270\320\265.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 02 - \320\230\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201. \320\236\321\201\320\275\320\276\320\262\321\213 \320\262\320\265\321\200\321\201\321\202\320\272\320\270. \320\241\320\277\320\270\321\201\320\272\320\270.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 02 - \320\230\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201. \320\236\321\201\320\275\320\276\320\262\321\213 \320\262\320\265\321\200\321\201\321\202\320\272\320\270. \320\241\320\277\320\270\321\201\320\272\320\270.pdf"
new file mode 100644
index 0000000..d396bbf
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 02 - \320\230\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201. \320\236\321\201\320\275\320\276\320\262\321\213 \320\262\320\265\321\200\321\201\321\202\320\272\320\270. \320\241\320\277\320\270\321\201\320\272\320\270.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 03 - Activity. Fragment. Lifecycle.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 03 - Activity. Fragment. Lifecycle.pdf"
new file mode 100644
index 0000000..042718f
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 03 - Activity. Fragment. Lifecycle.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 04 - \320\244\320\276\320\275\320\276\320\262\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260. \320\243\320\262\320\265\320\264\320\276\320\274\320\273\320\265\320\275\320\270\321\217.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 04 - \320\244\320\276\320\275\320\276\320\262\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260. \320\243\320\262\320\265\320\264\320\276\320\274\320\273\320\265\320\275\320\270\321\217.pdf"
new file mode 100644
index 0000000..9c5b15f
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 04 - \320\244\320\276\320\275\320\276\320\262\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260. \320\243\320\262\320\265\320\264\320\276\320\274\320\273\320\265\320\275\320\270\321\217.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 05 - \320\220\321\200\321\205\320\270\321\202\320\265\320\272\321\202\321\203\321\200\320\260 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\271.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 05 - \320\220\321\200\321\205\320\270\321\202\320\265\320\272\321\202\321\203\321\200\320\260 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\271.pdf"
new file mode 100644
index 0000000..4ce208a
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 05 - \320\220\321\200\321\205\320\270\321\202\320\265\320\272\321\202\321\203\321\200\320\260 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\271.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 07 - \320\245\321\200\320\260\320\275\320\265\320\275\320\270\320\265 \320\264\320\260\320\275\320\275\321\213\321\205, Content Provider.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 07 - \320\245\321\200\320\260\320\275\320\265\320\275\320\270\320\265 \320\264\320\260\320\275\320\275\321\213\321\205, Content Provider.pdf"
new file mode 100644
index 0000000..358bc44
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 07 - \320\245\321\200\320\260\320\275\320\265\320\275\320\270\320\265 \320\264\320\260\320\275\320\275\321\213\321\205, Content Provider.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 08 - Custom View, Animations, Touches.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 08 - Custom View, Animations, Touches.pdf"
new file mode 100644
index 0000000..9c5e266
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 08 - Custom View, Animations, Touches.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 09 - \320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 09 - \320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265.pdf"
new file mode 100644
index 0000000..1004409
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 09 - \320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265.pdf" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 10 - Android \320\270 \320\261\320\270\320\261\320\273\320\270\320\276\321\202\320\265\320\272\320\270.pdf" "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 10 - Android \320\270 \320\261\320\270\320\261\320\273\320\270\320\276\321\202\320\265\320\272\320\270.pdf"
new file mode 100644
index 0000000..8e7d773
Binary files /dev/null and "b/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 10 - Android \320\270 \320\261\320\270\320\261\320\273\320\270\320\276\321\202\320\265\320\272\320\270.pdf" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 06 - \320\234\320\275\320\276\320\263\320\276\320\277\320\276\321\202\320\276\321\207\320\275\320\276\321\201\321\202\321\214.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 01 - \320\222\321\201\321\202\321\203\320\277\320\273\320\265\320\275\320\270\320\265.pptx"
similarity index 73%
rename from "presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 06 - \320\234\320\275\320\276\320\263\320\276\320\277\320\276\321\202\320\276\321\207\320\275\320\276\321\201\321\202\321\214.pptx"
rename to "presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 01 - \320\222\321\201\321\202\321\203\320\277\320\273\320\265\320\275\320\270\320\265.pptx"
index c186936..f034b42 100644
Binary files "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 06 - \320\234\320\275\320\276\320\263\320\276\320\277\320\276\321\202\320\276\321\207\320\275\320\276\321\201\321\202\321\214.pptx" and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 01 - \320\222\321\201\321\202\321\203\320\277\320\273\320\265\320\275\320\270\320\265.pptx" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 02 - \320\230\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201. \320\236\321\201\320\275\320\276\320\262\321\213 \320\262\320\265\321\200\321\201\321\202\320\272\320\270. \320\241\320\277\320\270\321\201\320\272\320\270.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 02 - \320\230\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201. \320\236\321\201\320\275\320\276\320\262\321\213 \320\262\320\265\321\200\321\201\321\202\320\272\320\270. \320\241\320\277\320\270\321\201\320\272\320\270.pptx"
new file mode 100644
index 0000000..53b22b7
Binary files /dev/null and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 02 - \320\230\320\275\321\202\320\265\321\200\321\204\320\265\320\271\321\201. \320\236\321\201\320\275\320\276\320\262\321\213 \320\262\320\265\321\200\321\201\321\202\320\272\320\270. \320\241\320\277\320\270\321\201\320\272\320\270.pptx" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 03 - Activity. Fragment. Lifecycle.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 03 - Activity. Fragment. Lifecycle.pptx"
new file mode 100644
index 0000000..eb01083
Binary files /dev/null and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 03 - Activity. Fragment. Lifecycle.pptx" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 04 - \320\244\320\276\320\275\320\276\320\262\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260. \320\243\320\262\320\265\320\264\320\276\320\274\320\273\320\265\320\275\320\270\321\217.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 04 - \320\244\320\276\320\275\320\276\320\262\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260. \320\243\320\262\320\265\320\264\320\276\320\274\320\273\320\265\320\275\320\270\321\217.pptx"
new file mode 100644
index 0000000..5b5cbfd
Binary files /dev/null and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 04 - \320\244\320\276\320\275\320\276\320\262\320\260\321\217 \321\200\320\260\320\261\320\276\321\202\320\260. \320\243\320\262\320\265\320\264\320\276\320\274\320\273\320\265\320\275\320\270\321\217.pptx" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 05 - \320\220\321\200\321\205\320\270\321\202\320\265\320\272\321\202\321\203\321\200\320\260 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\271.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 05 - \320\220\321\200\321\205\320\270\321\202\320\265\320\272\321\202\321\203\321\200\320\260 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\271.pptx"
new file mode 100644
index 0000000..9c35eb2
Binary files /dev/null and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 05 - \320\220\321\200\321\205\320\270\321\202\320\265\320\272\321\202\321\203\321\200\320\260 \320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\271.pptx" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 07 - \320\245\321\200\320\260\320\275\320\265\320\275\320\270\320\265 \320\264\320\260\320\275\320\275\321\213\321\205, Content Provider.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 07 - \320\245\321\200\320\260\320\275\320\265\320\275\320\270\320\265 \320\264\320\260\320\275\320\275\321\213\321\205, Content Provider.pptx"
new file mode 100644
index 0000000..3a20a94
Binary files /dev/null and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 07 - \320\245\321\200\320\260\320\275\320\265\320\275\320\270\320\265 \320\264\320\260\320\275\320\275\321\213\321\205, Content Provider.pptx" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 08 - Custom View, Animations, Touches.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 08 - Custom View, Animations, Touches.pptx"
new file mode 100644
index 0000000..219d210
Binary files /dev/null and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 08 - Custom View, Animations, Touches.pptx" differ
diff --git "a/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 09 - \320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265.pptx" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 09 - \320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265.pptx"
new file mode 100644
index 0000000..24bb4b9
Binary files /dev/null and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 09 - \320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265.pptx" differ
diff --git "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 06 - \320\234\320\275\320\276\320\263\320\276\320\277\320\276\321\202\320\276\321\207\320\275\320\276\321\201\321\202\321\214.pdf" "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 10 - Android \320\270 \320\261\320\270\320\261\320\273\320\270\320\276\321\202\320\265\320\272\320\270.pptx"
similarity index 57%
rename from "presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 06 - \320\234\320\275\320\276\320\263\320\276\320\277\320\276\321\202\320\276\321\207\320\275\320\276\321\201\321\202\321\214.pdf"
rename to "presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 10 - Android \320\270 \320\261\320\270\320\261\320\273\320\270\320\276\321\202\320\265\320\272\320\270.pptx"
index 13a5698..5b30ed0 100644
Binary files "a/presentation/pdf/\320\233\320\265\320\272\321\206\320\270\321\217 06 - \320\234\320\275\320\276\320\263\320\276\320\277\320\276\321\202\320\276\321\207\320\275\320\276\321\201\321\202\321\214.pdf" and "b/presentation/pptx/\320\233\320\265\320\272\321\206\320\270\321\217 10 - Android \320\270 \320\261\320\270\320\261\320\273\320\270\320\276\321\202\320\265\320\272\320\270.pptx" differ