Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelspeedcode committed Jan 15, 2020
1 parent 3c69c6a commit ef03425
Show file tree
Hide file tree
Showing 49 changed files with 1,330 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
52 changes: 52 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 28
buildToolsVersion '28.0.3'

defaultConfig {
applicationId "com.aliasadi.mvvm"
minSdkVersion 23
targetSdkVersion 28
versionCode 1

versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {

implementation fileTree(dir: 'libs', include: ['*.jar'])

//android support
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'

//gson
implementation 'com.google.code.gson:gson:2.8.5'

//extensions
implementation "android.arch.lifecycle:extensions:1.1.1"

//coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

}
repositories {
mavenCentral()
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
28 changes: 28 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.speed.mvvm">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:name=".CSVApp"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity android:name="com.speed.mvvm.ui.main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.speed.mvvm.ui.details.DetailsActivity" />

</application>

</manifest>
19 changes: 19 additions & 0 deletions app/src/main/java/com/speed/mvvm/CSVApp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.speed.mvvm;

import android.app.Application;

public class CSVApp extends Application {

private static CSVApp sInstance;

public static CSVApp getInstance() {
return sInstance;
}

@Override
public void onCreate() {
super.onCreate();
sInstance = this;
}

}
37 changes: 37 additions & 0 deletions app/src/main/java/com/speed/mvvm/CSVReader.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.speed.mvvm

import com.speed.mvvm.data.network.model.Person
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.nio.charset.Charset

class CSVReader {
companion object {
fun createListFromFile(file: InputStream): List<Person>? {
val list: ArrayList<Person> = ArrayList()

val reader = BufferedReader(InputStreamReader(file, Charset.forName("UTF-8")))
reader.readLines().forEach {

val items = it.split(",")
try {
list.add(Person(replaceQuotationMarks(items[0]),
replaceQuotationMarks(items[1]),
replaceQuotationMarks(items[2]),
replaceQuotationMarks(items[3])))
} catch (e: IndexOutOfBoundsException) {
println("Item was malformed")
}
}

//remove first item with column descriptors
if (list.size > 0) list.removeAt(0)

return list
}

private fun replaceQuotationMarks(item: String) =
item.replace("\"", "")
}
}
25 changes: 25 additions & 0 deletions app/src/main/java/com/speed/mvvm/DateUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.speed.mvvm

import android.os.Build
import android.support.annotation.RequiresApi
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

class DateUtils {
companion object {

@RequiresApi(Build.VERSION_CODES.O)
fun formatDate(dateOfBirth: String?): String {
try {
if (dateOfBirth.isNullOrBlank()) return ""

val localDateTime: LocalDateTime = LocalDateTime.parse(dateOfBirth)
val formatter = DateTimeFormatter.ofPattern("dd MMM yyyy '-' hh:mma")
return formatter.format(localDateTime)
} catch (e: Throwable) {
return dateOfBirth ?: ""
}
}
}

}
17 changes: 17 additions & 0 deletions app/src/main/java/com/speed/mvvm/ViewExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.speed.mvvm

import android.app.Activity
import android.support.annotation.IdRes
import android.view.View

fun <T : View> Activity.bind(@IdRes idRes: Int): Lazy<T> {
@Suppress("UNCHECKED_CAST")
return unsafeLazy { findViewById<T>(idRes) }
}

fun <T : View> View.bind(@IdRes idRes: Int): Lazy<T> {
@Suppress("UNCHECKED_CAST")
return unsafeLazy { findViewById<T>(idRes) }
}

private fun <T> unsafeLazy(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer)
83 changes: 83 additions & 0 deletions app/src/main/java/com/speed/mvvm/data/network/model/Person.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.speed.mvvm.data.network.model

import android.os.Parcel
import android.os.Parcelable
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

class Person : Parcelable {
@Expose
@SerializedName("First name")
var firstName: String
private set
@Expose
@SerializedName("Sur name")
var surname: String
private set
@Expose
@SerializedName("Issue count")
var issueCount: String
private set
@Expose
@SerializedName("Date of birth")
var dateOfBirth: String
private set

protected constructor(`in`: Parcel) {
firstName = `in`.readString() ?: ""
surname = `in`.readString() ?: ""
issueCount = `in`.readString() ?: ""
dateOfBirth = `in`.readString() ?: ""
}

constructor(firstName: String, surname: String, issueCount: String, dateOfBirth: String) {
this.firstName = firstName
this.surname = surname
this.issueCount = issueCount
this.dateOfBirth = dateOfBirth
}


override fun describeContents(): Int {
return 0
}

override fun writeToParcel(parcel: Parcel, i: Int) {
parcel.writeString(firstName)
parcel.writeString(surname)
parcel.writeString(issueCount)
parcel.writeString(dateOfBirth)
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as Person

if (firstName != other.firstName) return false
if (surname != other.surname) return false
if (issueCount != other.issueCount) return false
if (dateOfBirth != other.dateOfBirth) return false

return true
}

override fun hashCode(): Int {
var result = firstName.hashCode()
result = 31 * result + surname.hashCode()
result = 31 * result + issueCount.hashCode()
result = 31 * result + dateOfBirth.hashCode()
return result
}

companion object CREATOR : Parcelable.Creator<Person> {
override fun createFromParcel(parcel: Parcel): Person {
return Person(parcel)
}

override fun newArray(size: Int): Array<Person?> {
return arrayOfNulls(size)
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/speed/mvvm/ui/base/BaseActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.speed.mvvm.ui.base

import android.os.Bundle
import android.support.v7.app.AppCompatActivity

abstract class BaseActivity<VM : BaseViewModel?> : AppCompatActivity() {
@JvmField
protected var viewModel: VM? = null
protected abstract fun createViewModel(): VM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = createViewModel()
}
}
5 changes: 5 additions & 0 deletions app/src/main/java/com/speed/mvvm/ui/base/BaseViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.speed.mvvm.ui.base

import android.arch.lifecycle.ViewModel

abstract class BaseViewModel : ViewModel()
59 changes: 59 additions & 0 deletions app/src/main/java/com/speed/mvvm/ui/details/DetailsActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.speed.mvvm.ui.details

import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.widget.TextView
import com.speed.mvvm.DateUtils
import com.speed.mvvm.R
import com.speed.mvvm.bind
import com.speed.mvvm.data.network.model.Person
import com.speed.mvvm.ui.base.BaseActivity

class DetailsActivity : BaseActivity<DetailsViewModel>() {

private val firstName by bind<TextView>(R.id.firstName)
private val surname by bind<TextView>(R.id.surname)
private val dateOfBirth by bind<TextView>(R.id.dateOfBirth)
private val issues by bind<TextView>(R.id.issues)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details)
viewModel?.loadPersonData()
viewModel?.personLiveData?.observe(this, PersonObserver())
}

override fun createViewModel(): DetailsViewModel {
val person: Person = intent.getParcelableExtra(EXTRA_PERSON)
val factory = DetailsViewModelFactory(person)
return ViewModelProviders.of(this, factory).get(DetailsViewModel::class.java)
}

private inner class PersonObserver : Observer<Person?> {
override fun onChanged(person: Person?) {
if (person == null) return
firstName.text = person.firstName
surname.text = person.surname
dateOfBirth.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
DateUtils.formatDate(person.dateOfBirth)
} else {
person.dateOfBirth
}
issues.text = person.issueCount
}
}

companion object {
private const val EXTRA_PERSON = "EXTRA_PERSON"
@JvmStatic
fun start(context: Context, person: Person?) {
val intent = Intent(context, DetailsActivity::class.java)
intent.putExtra(EXTRA_PERSON, person)
context.startActivity(intent)
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/speed/mvvm/ui/details/DetailsViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.speed.mvvm.ui.details

import android.arch.lifecycle.MutableLiveData
import com.speed.mvvm.data.network.model.Person
import com.speed.mvvm.ui.base.BaseViewModel

class DetailsViewModel(private var person: Person) : BaseViewModel() {
val personLiveData = MutableLiveData<Person>()

fun loadPersonData() {
personLiveData.postValue(person)
}

}
Loading

0 comments on commit ef03425

Please sign in to comment.