From 622cf980c4fb68efab546eeddf31c4bf5aee7ba1 Mon Sep 17 00:00:00 2001 From: Andrius Baruckis Date: Sat, 19 May 2018 18:18:18 +0300 Subject: [PATCH] chore: Reorganized gradle setup to separate versions. Added architecture components and ktx libraries. feat: Initial ViewModel setup for main screen. Initial data model setup. Main list adapter setup to use data model. --- .idea/copyright/Apache_V2.xml | 6 ++ .idea/copyright/profiles_settings.xml | 3 + app/build.gradle | 56 ++++++++++++------ app/src/main/AndroidManifest.xml | 2 +- .../mycryptocoins/data/Cryptocurrency.kt | 28 +++++++++ ...ityListFragment.kt => MainListFragment.kt} | 41 ++++++------- .../mainlist/MainRecyclerViewAdapter.kt | 58 ++++++++++++++++++- .../mycryptocoins/mainlist/MainViewModel.kt | 41 +++++++++++++ app/src/main/res/layout/activity_main.xml | 3 +- app/src/main/res/layout/content_main.xml | 2 +- .../main/res/layout/fragment_main_list.xml | 2 +- .../res/layout/fragment_main_list_item.xml | 7 +-- app/src/main/res/values/strings.xml | 2 + build.gradle | 21 ++----- versions.gradle | 42 ++++++++++++++ 15 files changed, 245 insertions(+), 69 deletions(-) create mode 100644 .idea/copyright/Apache_V2.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 app/src/main/java/com/baruckis/mycryptocoins/data/Cryptocurrency.kt rename app/src/main/java/com/baruckis/mycryptocoins/mainlist/{MainActivityListFragment.kt => MainListFragment.kt} (72%) create mode 100644 app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainViewModel.kt create mode 100644 versions.gradle diff --git a/.idea/copyright/Apache_V2.xml b/.idea/copyright/Apache_V2.xml new file mode 100644 index 0000000..b87dd4c --- /dev/null +++ b/.idea/copyright/Apache_V2.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..7d6de4b --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 2409b5f..2fa504c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,17 +15,17 @@ */ apply plugin: 'com.android.application' - apply plugin: 'kotlin-android' - apply plugin: 'kotlin-android-extensions' +// Version values at Project level versions.gradle. + android { - compileSdkVersion 27 + compileSdkVersion versions.compile_sdk defaultConfig { applicationId "com.baruckis.mycryptocoins" - minSdkVersion 23 - targetSdkVersion 27 + minSdkVersion versions.min_sdk + targetSdkVersion versions.target_sdk versionCode 1 versionName "@string/app_version" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -40,21 +40,43 @@ android { dependencies { - // Version values at Project level build.gradle. - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - // Android - implementation "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion" - implementation "com.android.support:cardview-v7:$rootProject.supportLibraryVersion" - implementation "com.android.support:design:$rootProject.supportLibraryVersion" - implementation "com.android.support.constraint:constraint-layout:$rootProject.constraintLayoutVersion" - 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' + // Kotlin + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" + + + /* Android */ + + // Support libraries + implementation "com.android.support:appcompat-v7:$versions.support" + implementation "com.android.support:cardview-v7:$versions.support" + implementation "com.android.support:design:$versions.support" + + // Constraint layout + implementation "com.android.support.constraint:constraint-layout:$versions.constraint_layout" + + // Android KTX + implementation "androidx.core:core-ktx:$versions.core" + + // Architecture components + // LiveData + ViewModel + implementation "android.arch.lifecycle:extensions:$versions.lifecycle" + + // Android Testing Support Library's runner and rules + androidTestImplementation "com.android.support.test:runner:$versions.atsl_runner" + + // Espresso UI Testing + androidTestImplementation "com.android.support.test.espresso:espresso-core:$versions.espresso" + + + /* Other */ + + // Dependencies for local unit tests + testImplementation "junit:junit:$versions.junit" // 3rd party - implementation "eu.davidea:flipview:$rootProject.flipViewVersion" + // UI + implementation "eu.davidea:flipview:$versions.flip_view" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b839619..36cf78f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ ~ 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/app/src/main/java/com/baruckis/mycryptocoins/data/Cryptocurrency.kt b/app/src/main/java/com/baruckis/mycryptocoins/data/Cryptocurrency.kt new file mode 100644 index 0000000..19a0a90 --- /dev/null +++ b/app/src/main/java/com/baruckis/mycryptocoins/data/Cryptocurrency.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Andrius Baruckis www.baruckis.com | mycryptocoins.baruckis.com + * + * 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. + */ + +package com.baruckis.mycryptocoins.data + +data class Cryptocurrency(val name: String, + val rank: Short, + val amount: Double, + val symbol: String, + val price: Double, + val amountFiat: Double, + val pricePercentChange1h: Double, + val pricePercentChange7d: Double, + val pricePercentChange24h: Double, + val amountFiatChange24h: Double) \ No newline at end of file diff --git a/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainActivityListFragment.kt b/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainListFragment.kt similarity index 72% rename from app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainActivityListFragment.kt rename to app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainListFragment.kt index c7b6448..3179fed 100644 --- a/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainActivityListFragment.kt +++ b/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainListFragment.kt @@ -16,6 +16,8 @@ package com.baruckis.mycryptocoins.mainlist +import android.arch.lifecycle.Observer +import android.arch.lifecycle.ViewModelProviders import android.os.Bundle import android.support.v4.app.Fragment import android.support.v7.widget.LinearLayoutManager @@ -28,11 +30,13 @@ import com.baruckis.mycryptocoins.R /** * A placeholder fragment containing a simple view. */ -class MainActivityListFragment : Fragment() { +class MainListFragment : Fragment() { private lateinit var recyclerView: RecyclerView private lateinit var recyclerAdapter: MainRecyclerViewAdapter + private lateinit var viewModel: MainViewModel + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val v: View = inflater.inflate(R.layout.fragment_main_list, container, false) @@ -47,33 +51,22 @@ class MainActivityListFragment : Fragment() { super.onActivityCreated(savedInstanceState) setupList() - } - private fun setupList() { + // Obtain ViewModel from ViewModelProviders, using this fragment as LifecycleOwner. + viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) - val data = ArrayList() - data.add("Bitcoin") - data.add("Etherium") - data.add("Ripple") - data.add("Bitcoin Cash") - data.add("Litecoin") - data.add("NEO") - data.add("Stellar") - data.add("EOS") - data.add("Cardano") - data.add("Stellar") - data.add("IOTA") - data.add("Dash") - data.add("Monero") - data.add("TRON") - data.add("NEM") - data.add("ICON") - data.add("Bitcoin Gold") - data.add("Zcash") - data.add("Verge") + // Observe data on the ViewModel, exposed as a LiveData + viewModel.data.observe(this, Observer { data -> + // Set the data exposed by the LiveData + if (data != null) { + recyclerAdapter.setData(data) + } + }) + } + private fun setupList() { recyclerView.layoutManager = LinearLayoutManager(activity) - recyclerAdapter = MainRecyclerViewAdapter(data) + recyclerAdapter = MainRecyclerViewAdapter() recyclerView.adapter = recyclerAdapter } } diff --git a/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainRecyclerViewAdapter.kt b/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainRecyclerViewAdapter.kt index 3ec3aad..2bd888a 100644 --- a/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainRecyclerViewAdapter.kt +++ b/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainRecyclerViewAdapter.kt @@ -16,15 +16,29 @@ package com.baruckis.mycryptocoins.mainlist +import android.content.Context +import android.support.v4.content.ContextCompat import android.support.v7.widget.RecyclerView +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.style.ForegroundColorSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView +import androidx.core.text.plusAssign +import androidx.core.text.toSpannable import com.baruckis.mycryptocoins.R +import com.baruckis.mycryptocoins.data.Cryptocurrency -class MainRecyclerViewAdapter(val dataList: ArrayList) : RecyclerView.Adapter() { +class MainRecyclerViewAdapter() : RecyclerView.Adapter() { + + private lateinit var dataList: ArrayList + + fun setData(newDataList: ArrayList) { + dataList = newDataList + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { val v = LayoutInflater.from(parent.context).inflate(R.layout.fragment_main_list_item, parent, false) @@ -32,16 +46,56 @@ class MainRecyclerViewAdapter(val dataList: ArrayList) : RecyclerView.Ad } override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { - holder.txtName?.text = dataList[position] + holder.txtName?.text = dataList[position].name + holder.txtRanking?.text = String.format("${dataList[position].rank}") + holder.txtAmountAndSymbol?.text = String.format("${dataList[position].amount} ${dataList[position].symbol}") + holder.txtPrice?.text = String.format("${dataList[position].price} ${holder.context.getString(R.string.pref_default_fiat_currency_value)}") + holder.txtAmountFiat?.text = String.format("${dataList[position].amountFiat} ${holder.context.getString(R.string.pref_default_fiat_currency_value)}") + holder.txtPricePercentChange1hAnd7d?.text = + SpannableStringBuilder(getChangeValueStyled(dataList[position].pricePercentChange1h, holder.context)) + .append(holder.context.getString(R.string.string_column_coin_separator_change)) + .append(getChangeValueStyled(dataList[position].pricePercentChange7d, holder.context)) + holder.txtPricePercentChange24h?.text = getChangeValueStyled(dataList[position].pricePercentChange24h, holder.context) + holder.txtAmountFiatChange24h?.text = getChangeValueStyled(dataList[position].amountFiatChange24h, holder.context, true) } override fun getItemCount(): Int { return dataList.size } + private fun getChangeValueStyled(value:Double, context:Context, isFiat:Boolean = false): Spannable { + val valueString:String = String.format("$value").plus(if (isFiat) " ${context.getString(R.string.pref_default_fiat_currency_value)}" else "%") + val valueSpannable:Spannable + + when { + value > 0 -> { + valueSpannable = "+$valueString".toSpannable() + valueSpannable.plusAssign(ForegroundColorSpan(ContextCompat.getColor(context, R.color.colorForValueChangePositive))) + } + value < 0 -> { + valueSpannable = valueString.toSpannable() + valueSpannable.plusAssign(ForegroundColorSpan(ContextCompat.getColor(context, R.color.colorForValueChangeNegative))) + } + else -> { + valueSpannable = valueString.toSpannable() + valueSpannable.plusAssign(ForegroundColorSpan(ContextCompat.getColor(context, R.color.colorForMainListItemText))) + } + } + return valueSpannable + } + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val context:Context = itemView.context + val txtName = itemView.findViewById(R.id.item_name) + val txtRanking = itemView.findViewById(R.id.item_ranking) + val txtAmountAndSymbol = itemView.findViewById(R.id.item_amount_symbol) + val txtPrice = itemView.findViewById(R.id.item_price) + val txtAmountFiat = itemView.findViewById(R.id.item_amount_fiat) + val txtPricePercentChange1hAnd7d = itemView.findViewById(R.id.item_price_percent_change_1h_7d) + val txtPricePercentChange24h = itemView.findViewById(R.id.item_price_percent_change_24h) + val txtAmountFiatChange24h = itemView.findViewById(R.id.item_amount_fiat_change_24h) } } \ No newline at end of file diff --git a/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainViewModel.kt b/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainViewModel.kt new file mode 100644 index 0000000..902a430 --- /dev/null +++ b/app/src/main/java/com/baruckis/mycryptocoins/mainlist/MainViewModel.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2018 Andrius Baruckis www.baruckis.com | mycryptocoins.baruckis.com + * + * 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. + */ + +package com.baruckis.mycryptocoins.mainlist + +import android.arch.lifecycle.LiveData +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.ViewModel +import com.baruckis.mycryptocoins.data.Cryptocurrency + +class MainViewModel : ViewModel() { + + private val liveData = MutableLiveData>() + val data: LiveData> + get() = liveData + + init { + val tempData = ArrayList() + + val btc:Cryptocurrency = Cryptocurrency("Bitcoin", 1, 0.56822348, "BTC", 8328.77, 4732.60, 0.19, -10.60, 0.44, 20.82) + val eth:Cryptocurrency = Cryptocurrency("Etherium", 2, 6.0, "ETH", 702.99, 4217.94, 0.13, -7.38, 0.79, 33.32) + + tempData.add(btc) + tempData.add(eth) + + liveData.value = tempData + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 76ef28f..8186e05 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -73,9 +73,8 @@ android:id="@+id/textview_total_value_change_24h" style="@style/AutoSizeText" android:layout_width="wrap_content" - android:background="@color/colorForValueChangePositive" android:gravity="center" - android:text="@string/sample_text_total_value_change_24h" + android:text="@string/string_total_value_change_24h" android:textAlignment="center" android:textColor="@color/colorWhite" android:textDirection="firstStrongLtr" diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 7e1eb07..84fe770 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -18,7 +18,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/fragment" - android:name="com.baruckis.mycryptocoins.mainlist.MainActivityListFragment" + android:name="com.baruckis.mycryptocoins.mainlist.MainListFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" diff --git a/app/src/main/res/layout/fragment_main_list.xml b/app/src/main/res/layout/fragment_main_list.xml index 31d30ea..396238b 100644 --- a/app/src/main/res/layout/fragment_main_list.xml +++ b/app/src/main/res/layout/fragment_main_list.xml @@ -20,7 +20,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context="com.baruckis.mycryptocoins.mainlist.MainActivityListFragment" + tools:context="com.baruckis.mycryptocoins.mainlist.MainListFragment" tools:showIn="@layout/activity_main"> "Crypto coin\nAmount & symbol" "Price $\nAmount $" "± price % 1 h / 7 d\n± price % 24 h\n± amount $ 24 h" + " / " "Total holdings value (11/03/2018 12:55:08)" " $ +1538.00 " @@ -55,6 +56,7 @@ "+4.25%" "+1,053.12 USD" + "&usd;" "&aud;" diff --git a/build.gradle b/build.gradle index 819077a..7bfdc45 100644 --- a/build.gradle +++ b/build.gradle @@ -17,14 +17,16 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.2.41' + apply from: 'versions.gradle' + repositories { google() jcenter() } + dependencies { - classpath 'com.android.tools.build:gradle:3.1.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "com.android.tools.build:gradle:$versions.android_gradle_plugin" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -40,17 +42,4 @@ allprojects { task clean(type: Delete) { delete rootProject.buildDir -} - -ext { - - // 3rd party - flipViewVersion = '1.1.3' - - // Android - supportLibraryVersion = '27.1.1' - constraintLayoutVersion = '1.1.0' - archLifecycleVersion = '1.0.3' - archLifecycleCompilerVersion = '1.0.0' - archLifecycleExtensionsVersion = '1.0.0' } \ No newline at end of file diff --git a/versions.gradle b/versions.gradle new file mode 100644 index 0000000..dde5869 --- /dev/null +++ b/versions.gradle @@ -0,0 +1,42 @@ +/* + * Copyright 2018 Andrius Baruckis www.baruckis.com | mycryptocoins.baruckis.com + * + * 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. + */ + +def versions = [:] + +versions.kotlin = "1.2.41" +versions.android_gradle_plugin = "3.1.2" + +versions.min_sdk = 21 +versions.compile_sdk = 27 +versions.target_sdk = 27 + + +versions.support = "27.1.1" +versions.constraint_layout = "1.1.0" + +versions.core = "0.3" +versions.lifecycle = "1.1.1" + + +versions.atsl_runner = "1.0.2" +versions.espresso = "3.0.2" + +versions.junit = "4.12" + +versions.flip_view = "1.1.3" + + +ext.versions = versions \ No newline at end of file