From 971bbe27ab85f28800ceff1d66a079ec1958ec0b Mon Sep 17 00:00:00 2001 From: Anel CC Date: Sat, 11 Apr 2020 09:08:57 -0400 Subject: [PATCH 1/9] [Anel] Model an entity in a Kotlin data class --- .../java/com/anelcc/monster/MainViewModel.kt | 2 + .../java/com/anelcc/monster/data/Monster.kt | 10 ++ .../com/anelcc/monster/main/MainFragment.kt | 102 ++++++++++++++++++ app/src/main/res/layout/fragment_main.xml | 14 +++ app/src/main/res/raw/monster_data.json | 98 +++++++++++++++++ 5 files changed, 226 insertions(+) create mode 100644 app/src/main/java/com/anelcc/monster/MainViewModel.kt create mode 100644 app/src/main/java/com/anelcc/monster/data/Monster.kt create mode 100644 app/src/main/java/com/anelcc/monster/main/MainFragment.kt create mode 100644 app/src/main/res/layout/fragment_main.xml create mode 100644 app/src/main/res/raw/monster_data.json diff --git a/app/src/main/java/com/anelcc/monster/MainViewModel.kt b/app/src/main/java/com/anelcc/monster/MainViewModel.kt new file mode 100644 index 0000000..980e876 --- /dev/null +++ b/app/src/main/java/com/anelcc/monster/MainViewModel.kt @@ -0,0 +1,2 @@ +package com.anelcc.monster + diff --git a/app/src/main/java/com/anelcc/monster/data/Monster.kt b/app/src/main/java/com/anelcc/monster/data/Monster.kt new file mode 100644 index 0000000..510b540 --- /dev/null +++ b/app/src/main/java/com/anelcc/monster/data/Monster.kt @@ -0,0 +1,10 @@ +package com.anelcc.monster.data + +data class Monster ( + val monsterName: String, + val imageFile: String, + val caption: String, + val description: String, + val price: Double, + val scariness: Int +) diff --git a/app/src/main/java/com/anelcc/monster/main/MainFragment.kt b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt new file mode 100644 index 0000000..f7373a8 --- /dev/null +++ b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt @@ -0,0 +1,102 @@ +package com.anelcc.monster.main + +import android.content.Context +import android.net.Uri +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.anelcc.monster.R + +// TODO: Rename parameter arguments, choose names that match +// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER +private const val ARG_PARAM1 = "param1" +private const val ARG_PARAM2 = "param2" + +/** + * A simple [Fragment] subclass. + * Activities that contain this fragment must implement the + * [MainFragment.OnFragmentInteractionListener] interface + * to handle interaction events. + * Use the [MainFragment.newInstance] factory method to + * create an instance of this fragment. + */ +class MainFragment : Fragment() { + // TODO: Rename and change types of parameters + private var param1: String? = null + private var param2: String? = null + private var listener: OnFragmentInteractionListener? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + param1 = it.getString(ARG_PARAM1) + param2 = it.getString(ARG_PARAM2) + } + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_main, container, false) + } + + // TODO: Rename method, update argument and hook method into UI event + fun onButtonPressed(uri: Uri) { + listener?.onFragmentInteraction(uri) + } + + override fun onAttach(context: Context) { + super.onAttach(context) + if (context is OnFragmentInteractionListener) { + listener = context + } else { + throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener") + } + } + + override fun onDetach() { + super.onDetach() + listener = null + } + + /** + * This interface must be implemented by activities that contain this + * fragment to allow an interaction in this fragment to be communicated + * to the activity and potentially other fragments contained in that + * activity. + * + * + * See the Android Training lesson [Communicating with Other Fragments] + * (http://developer.android.com/training/basics/fragments/communicating.html) + * for more information. + */ + interface OnFragmentInteractionListener { + // TODO: Update argument type and name + fun onFragmentInteraction(uri: Uri) + } + + companion object { + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @param param1 Parameter 1. + * @param param2 Parameter 2. + * @return A new instance of fragment MainFragment. + */ + // TODO: Rename and change types and number of parameters + @JvmStatic + fun newInstance(param1: String, param2: String) = + MainFragment().apply { + arguments = Bundle().apply { + putString(ARG_PARAM1, param1) + putString(ARG_PARAM2, param2) + } + } + } +} diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml new file mode 100644 index 0000000..95e9363 --- /dev/null +++ b/app/src/main/res/layout/fragment_main.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/raw/monster_data.json b/app/src/main/res/raw/monster_data.json new file mode 100644 index 0000000..c81f8c0 --- /dev/null +++ b/app/src/main/res/raw/monster_data.json @@ -0,0 +1,98 @@ +[ + { + "imageFile": "monster01", + "monsterName": "Mingle", + "caption": "Double Trouble", + "description": "Mingle excels at doing twice the work in half the time, with pinpoint accuracy. These skills serve her well in her role as Senior Data Analyst for an international cloud computing company. She's also got a penchant for ballroom dance, line dancing, and pretty much any kind of activity that lets her groove to music.", + "price": 0.29, + "scariness": 2 + }, + { + "imageFile": "monster02", + "monsterName": "Yodel", + "caption": "Yodelay Hee Hoo!", + "description": "Yodel grew up in a family of singers and loud talkers and could never get a word in edgewise. Then his vast talent for yodeling emerged. Now he performs to adoring fans throughout the world, and always has the loudest voice at the dinner table. Incidentally, he's also a loud proponent of net neutrality, and spends countless hours moderating an internet forum devoted solely to that subject.", + "price": 0.19, + "scariness": 4 + }, + { + "imageFile": "monster03", + "monsterName": "Squido", + "caption": "An Eye for Design", + "description": "Squido's got his hands or rather tentacles, in everything. First and foremost, he's a web designer with an eye for visual aesthetics, but he's also rather keen on UX design and making sure what he creates translates optimally to the end user. In his off-hours he's an avid nature photographer and bowler.", + "price": 0.29, + "scariness": 3 + }, + { + "imageFile": "monster04", + "monsterName": "Spook", + "caption": "Safe and Sound", + "description": "Cracking code and battling hackers is Spook's forte. She holds a prominent position as Head of Cyber Security for the Department of Monster Defense, where she thwarts attacks on government computer systems as often as she blinks. When not at work, Spook delights in serving up a fright at haunted mansions and ghost walks.", + "price": 0.29, + "scariness": 5 + }, + { + "imageFile": "monster05", + "monsterName": "Melville", + "caption": "Networking Guru", + "description": "Setting up computer networks has always come easily to Melville. In his role as Senior Network Engineer for Landon Hotel, Melville builds complex blueprints for communication networks, a task that requires enormous attention to detail and patience. When not at work, Melville chooses less taxing mental activities, like hiking in the hills near his Silicon Valley home.", + "price": 0.19, + "scariness": 2 + }, + { + "imageFile": "monster06", + "monsterName": "Filo", + "caption": "Baker by Day, Techie by Night", + "description": "Filo was named after the wonderful, buttery pastry crust that monsters adore. She’s a prominent baker and pastry chef in monster circles and is always exploring and sharing new dessert trends. In her off time, however, she's quite the techie and dabbles in web and mobile app development. She even built a custom cake ordering app for her pastry business.", + "price": 0.29, + "scariness": 3 + }, + { + "imageFile": "monster07", + "monsterName": "Blade", + "caption": "Monster APPetite", + "description": "Blade freelances as a mobile app developer and has built some of the most popular Android and iOS apps used in modern monster society, including the award-winning Monster APPetite, which tracks calorie consumption and activity for the health-conscious monster. In his spare time, he competes in national agility contests with his border collie Winston.", + "price": 0.29, + "scariness": 5 + }, + { + "imageFile": "monster08", + "monsterName": "Timber", + "caption": "Database Expert", + "description": "A natural-born problem-solver, Timber's especially excited to solve complex business problems using databases. As a database administrator for Globe Bank International, he's able to flex his mental muscles using his certifications in Oracle, Microsoft SQL Server, and MySQL. When not behind the computer, Timber can often be found biking, surfing, or lounging around with a good detective novel.", + "price": 0.19, + "scariness": 2 + }, + { + "imageFile": "monster09", + "monsterName": "Skedaddle", + "caption": "Game of Life", + "description": "When Skedaddle was a teenager, his parents couldn't keep him away from his Game Boy. In fact, they seriously worried that he might not find a suitable career. Now as a prominent game developer for Red30 Tech, he's found his true calling…and put his family's worries to rest. You probably could have guessed this, but in his spare time Skedaddle loves to pay computer games.", + "price": 0.29, + "scariness": 4 + }, + { + "imageFile": "monster10", + "monsterName": "Smiley", + "caption": "Don’t Worry, Be Happy!", + "description": "With the bad rap they get from movies, monsters have it pretty tough. Perhaps no monster has done more to squash stereotypes than Smiley, who can take anyone’s frown and turn it upside down. That's why Smiley has a reputation as the best computer support specialist on her IT team, three years running.", + "price": 0.29, + "scariness": 1 + }, + { + "imageFile": "monster11", + "monsterName": "Frex", + "caption": "Born Leader", + "description": "Frex has always had a knack for leadership, starting from his days of being a Monster Scout. After studying computer science in college, and working as an IT specialist at several large companies, he naturally followed the management path. Now, as an IT manager for a Fortune 500 company, he gets to put his technical know-how to work, while also leading a team of talented engineers. Frex's hobbies include golf, billiards, and community service.", + "price": 0.19, + "scariness": 3 + }, + { + "imageFile": "monster12", + "monsterName": "Drift", + "caption": "In the Clouds", + "description": "After years of everyone saying her head was in the clouds, Drift found her calling as a software engineer developing a well-known cloud solution for the computing giant, Red30 Tech. After work, she prefers to unwind by catching wind in her sail and paragliding high in the sky.", + "price": 0.29, + "scariness": 4 + } +] \ No newline at end of file From 8d708d45bff1b346967272be3f0d55fcacc20665 Mon Sep 17 00:00:00 2001 From: Anel CC Date: Sat, 11 Apr 2020 09:08:57 -0400 Subject: [PATCH 2/9] [Anel] Model an entity in a Kotlin data class all --- app/build.gradle | 13 ++- .../java/com/anelcc/monster/MainViewModel.kt | 6 ++ .../com/anelcc/monster/main/MainFragment.kt | 97 ++++--------------- app/src/main/res/values/strings.xml | 3 + 4 files changed, 39 insertions(+), 80 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index bbade9a..c9089cf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,11 +25,20 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' -} + + + // KTX + implementation 'androidx.core:core-ktx:1.0.1' + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" + + + // This container view models and data + implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"} diff --git a/app/src/main/java/com/anelcc/monster/MainViewModel.kt b/app/src/main/java/com/anelcc/monster/MainViewModel.kt index 980e876..364096d 100644 --- a/app/src/main/java/com/anelcc/monster/MainViewModel.kt +++ b/app/src/main/java/com/anelcc/monster/MainViewModel.kt @@ -1,2 +1,8 @@ package com.anelcc.monster +import androidx.lifecycle.ViewModel + + +class MainViewModel : ViewModel() { + // TODO: Implement the ViewModel +} diff --git a/app/src/main/java/com/anelcc/monster/main/MainFragment.kt b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt index f7373a8..a97bf6f 100644 --- a/app/src/main/java/com/anelcc/monster/main/MainFragment.kt +++ b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt @@ -1,102 +1,43 @@ package com.anelcc.monster.main -import android.content.Context -import android.net.Uri + import android.os.Bundle +import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.ViewModelProvider +import com.anelcc.monster.MainViewModel import com.anelcc.monster.R +import com.anelcc.monster.data.Monster -// TODO: Rename parameter arguments, choose names that match -// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER -private const val ARG_PARAM1 = "param1" -private const val ARG_PARAM2 = "param2" - -/** - * A simple [Fragment] subclass. - * Activities that contain this fragment must implement the - * [MainFragment.OnFragmentInteractionListener] interface - * to handle interaction events. - * Use the [MainFragment.newInstance] factory method to - * create an instance of this fragment. - */ class MainFragment : Fragment() { - // TODO: Rename and change types of parameters - private var param1: String? = null - private var param2: String? = null - private var listener: OnFragmentInteractionListener? = null - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - arguments?.let { - param1 = it.getString(ARG_PARAM1) - param2 = it.getString(ARG_PARAM2) - } + + companion object { + fun newInstance() = MainFragment() } + private lateinit var viewModel: MainViewModel + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_main, container, false) - } + ): View { - // TODO: Rename method, update argument and hook method into UI event - fun onButtonPressed(uri: Uri) { - listener?.onFragmentInteraction(uri) - } - - override fun onAttach(context: Context) { - super.onAttach(context) - if (context is OnFragmentInteractionListener) { - listener = context - } else { - throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener") - } - } + val monster = Monster("Bob", "myfile", "a caption", + "a description", .19, 3) + Log.i("monsterLogging", monster.toString()) - override fun onDetach() { - super.onDetach() - listener = null + return inflater.inflate(R.layout.fragment_main, container, false) } - /** - * This interface must be implemented by activities that contain this - * fragment to allow an interaction in this fragment to be communicated - * to the activity and potentially other fragments contained in that - * activity. - * - * - * See the Android Training lesson [Communicating with Other Fragments] - * (http://developer.android.com/training/basics/fragments/communicating.html) - * for more information. - */ - interface OnFragmentInteractionListener { - // TODO: Update argument type and name - fun onFragmentInteraction(uri: Uri) + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + viewModel = ViewModelProvider(this).get(MainViewModel::class.java) + // TODO: Use the ViewModel } - companion object { - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @param param1 Parameter 1. - * @param param2 Parameter 2. - * @return A new instance of fragment MainFragment. - */ - // TODO: Rename and change types and number of parameters - @JvmStatic - fun newInstance(param1: String, param2: String) = - MainFragment().apply { - arguments = Bundle().apply { - putString(ARG_PARAM1, param1) - putString(ARG_PARAM2, param2) - } - } - } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index acbd736..b1e7a89 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,6 @@ Monster + + + Hello blank fragment From 802941c442c6680f2879c116afc22a82e8aff65e Mon Sep 17 00:00:00 2001 From: Anel CC Date: Sat, 11 Apr 2020 10:08:57 -0400 Subject: [PATCH 3/9] [Anel] Instance Fragment and use Nav Graf --- app/build.gradle | 6 +++++- app/src/main/java/com/anelcc/monster/Global.kt | 2 ++ .../com/anelcc/monster/utilities/FileHelper.kt | 2 ++ app/src/main/res/layout/activity_main.xml | 15 +++++++-------- app/src/main/res/navigation/nav_graph.xml | 13 +++++++++++++ 5 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/anelcc/monster/Global.kt create mode 100644 app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt create mode 100644 app/src/main/res/navigation/nav_graph.xml diff --git a/app/build.gradle b/app/build.gradle index c9089cf..3167881 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,6 +34,9 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + // KTN Android Components navigation + implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1' + implementation 'androidx.navigation:navigation-ui-ktx:2.2.1' // KTX implementation 'androidx.core:core-ktx:1.0.1' @@ -41,4 +44,5 @@ dependencies { // This container view models and data - implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"} + implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" +} diff --git a/app/src/main/java/com/anelcc/monster/Global.kt b/app/src/main/java/com/anelcc/monster/Global.kt new file mode 100644 index 0000000..980e876 --- /dev/null +++ b/app/src/main/java/com/anelcc/monster/Global.kt @@ -0,0 +1,2 @@ +package com.anelcc.monster + diff --git a/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt b/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt new file mode 100644 index 0000000..2cb1f57 --- /dev/null +++ b/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt @@ -0,0 +1,2 @@ +package com.anelcc.monster.utilities + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4fc2444..4ecbf01 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,13 +6,12 @@ android:layout_height="match_parent" tools:context=".MainActivity"> - + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml new file mode 100644 index 0000000..c5cad7a --- /dev/null +++ b/app/src/main/res/navigation/nav_graph.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file From f299cf86ad1fdd06328c9bdbeddef36866870c00 Mon Sep 17 00:00:00 2001 From: Anel CC Date: Sat, 11 Apr 2020 01:11:10 -0400 Subject: [PATCH 4/9] [Anel] Read files from resources --- app/src/main/java/com/anelcc/monster/Global.kt | 1 + .../main/java/com/anelcc/monster/MainViewModel.kt | 11 +++++++++-- .../com/anelcc/monster/utilities/FileHelper.kt | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/anelcc/monster/Global.kt b/app/src/main/java/com/anelcc/monster/Global.kt index 980e876..f00d15b 100644 --- a/app/src/main/java/com/anelcc/monster/Global.kt +++ b/app/src/main/java/com/anelcc/monster/Global.kt @@ -1,2 +1,3 @@ package com.anelcc.monster +const val LOG_TAG = "monsterLogging" \ No newline at end of file diff --git a/app/src/main/java/com/anelcc/monster/MainViewModel.kt b/app/src/main/java/com/anelcc/monster/MainViewModel.kt index 364096d..e9ef469 100644 --- a/app/src/main/java/com/anelcc/monster/MainViewModel.kt +++ b/app/src/main/java/com/anelcc/monster/MainViewModel.kt @@ -1,8 +1,15 @@ package com.anelcc.monster -import androidx.lifecycle.ViewModel +import android.app.Application +import android.util.Log +import androidx.lifecycle.AndroidViewModel +import com.anelcc.monster.utilities.FileHelper -class MainViewModel : ViewModel() { +class MainViewModel(app: Application) : AndroidViewModel(app) { // TODO: Implement the ViewModel + init { + val text = FileHelper.getTextFromResources(app, R.raw.monster_data) + Log.i(LOG_TAG, text) + } } diff --git a/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt b/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt index 2cb1f57..acf751e 100644 --- a/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt +++ b/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt @@ -1,2 +1,16 @@ package com.anelcc.monster.utilities +import android.content.Context + +class FileHelper { + //In java you create Static methods in Kotlin you function member of the companions + companion object { + fun getTextFromResources(context: Context, resourceId: Int): String { + return context.resources.openRawResource(resourceId).use { + it.bufferedReader().use { + it.readText() + } + } + } + } +} \ No newline at end of file From a8dd5ab710829d50fec3aa305e4bf36a93fcf770 Mon Sep 17 00:00:00 2001 From: Anel CC Date: Sun, 12 Apr 2020 15:25:10 -0400 Subject: [PATCH 5/9] [Anel] Read files from assets --- app/src/main/assets/monster_data.json | 98 +++++++++++++++++++ .../java/com/anelcc/monster/MainViewModel.kt | 8 +- .../anelcc/monster/utilities/FileHelper.kt | 9 ++ 3 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 app/src/main/assets/monster_data.json diff --git a/app/src/main/assets/monster_data.json b/app/src/main/assets/monster_data.json new file mode 100644 index 0000000..c81f8c0 --- /dev/null +++ b/app/src/main/assets/monster_data.json @@ -0,0 +1,98 @@ +[ + { + "imageFile": "monster01", + "monsterName": "Mingle", + "caption": "Double Trouble", + "description": "Mingle excels at doing twice the work in half the time, with pinpoint accuracy. These skills serve her well in her role as Senior Data Analyst for an international cloud computing company. She's also got a penchant for ballroom dance, line dancing, and pretty much any kind of activity that lets her groove to music.", + "price": 0.29, + "scariness": 2 + }, + { + "imageFile": "monster02", + "monsterName": "Yodel", + "caption": "Yodelay Hee Hoo!", + "description": "Yodel grew up in a family of singers and loud talkers and could never get a word in edgewise. Then his vast talent for yodeling emerged. Now he performs to adoring fans throughout the world, and always has the loudest voice at the dinner table. Incidentally, he's also a loud proponent of net neutrality, and spends countless hours moderating an internet forum devoted solely to that subject.", + "price": 0.19, + "scariness": 4 + }, + { + "imageFile": "monster03", + "monsterName": "Squido", + "caption": "An Eye for Design", + "description": "Squido's got his hands or rather tentacles, in everything. First and foremost, he's a web designer with an eye for visual aesthetics, but he's also rather keen on UX design and making sure what he creates translates optimally to the end user. In his off-hours he's an avid nature photographer and bowler.", + "price": 0.29, + "scariness": 3 + }, + { + "imageFile": "monster04", + "monsterName": "Spook", + "caption": "Safe and Sound", + "description": "Cracking code and battling hackers is Spook's forte. She holds a prominent position as Head of Cyber Security for the Department of Monster Defense, where she thwarts attacks on government computer systems as often as she blinks. When not at work, Spook delights in serving up a fright at haunted mansions and ghost walks.", + "price": 0.29, + "scariness": 5 + }, + { + "imageFile": "monster05", + "monsterName": "Melville", + "caption": "Networking Guru", + "description": "Setting up computer networks has always come easily to Melville. In his role as Senior Network Engineer for Landon Hotel, Melville builds complex blueprints for communication networks, a task that requires enormous attention to detail and patience. When not at work, Melville chooses less taxing mental activities, like hiking in the hills near his Silicon Valley home.", + "price": 0.19, + "scariness": 2 + }, + { + "imageFile": "monster06", + "monsterName": "Filo", + "caption": "Baker by Day, Techie by Night", + "description": "Filo was named after the wonderful, buttery pastry crust that monsters adore. She’s a prominent baker and pastry chef in monster circles and is always exploring and sharing new dessert trends. In her off time, however, she's quite the techie and dabbles in web and mobile app development. She even built a custom cake ordering app for her pastry business.", + "price": 0.29, + "scariness": 3 + }, + { + "imageFile": "monster07", + "monsterName": "Blade", + "caption": "Monster APPetite", + "description": "Blade freelances as a mobile app developer and has built some of the most popular Android and iOS apps used in modern monster society, including the award-winning Monster APPetite, which tracks calorie consumption and activity for the health-conscious monster. In his spare time, he competes in national agility contests with his border collie Winston.", + "price": 0.29, + "scariness": 5 + }, + { + "imageFile": "monster08", + "monsterName": "Timber", + "caption": "Database Expert", + "description": "A natural-born problem-solver, Timber's especially excited to solve complex business problems using databases. As a database administrator for Globe Bank International, he's able to flex his mental muscles using his certifications in Oracle, Microsoft SQL Server, and MySQL. When not behind the computer, Timber can often be found biking, surfing, or lounging around with a good detective novel.", + "price": 0.19, + "scariness": 2 + }, + { + "imageFile": "monster09", + "monsterName": "Skedaddle", + "caption": "Game of Life", + "description": "When Skedaddle was a teenager, his parents couldn't keep him away from his Game Boy. In fact, they seriously worried that he might not find a suitable career. Now as a prominent game developer for Red30 Tech, he's found his true calling…and put his family's worries to rest. You probably could have guessed this, but in his spare time Skedaddle loves to pay computer games.", + "price": 0.29, + "scariness": 4 + }, + { + "imageFile": "monster10", + "monsterName": "Smiley", + "caption": "Don’t Worry, Be Happy!", + "description": "With the bad rap they get from movies, monsters have it pretty tough. Perhaps no monster has done more to squash stereotypes than Smiley, who can take anyone’s frown and turn it upside down. That's why Smiley has a reputation as the best computer support specialist on her IT team, three years running.", + "price": 0.29, + "scariness": 1 + }, + { + "imageFile": "monster11", + "monsterName": "Frex", + "caption": "Born Leader", + "description": "Frex has always had a knack for leadership, starting from his days of being a Monster Scout. After studying computer science in college, and working as an IT specialist at several large companies, he naturally followed the management path. Now, as an IT manager for a Fortune 500 company, he gets to put his technical know-how to work, while also leading a team of talented engineers. Frex's hobbies include golf, billiards, and community service.", + "price": 0.19, + "scariness": 3 + }, + { + "imageFile": "monster12", + "monsterName": "Drift", + "caption": "In the Clouds", + "description": "After years of everyone saying her head was in the clouds, Drift found her calling as a software engineer developing a well-known cloud solution for the computing giant, Red30 Tech. After work, she prefers to unwind by catching wind in her sail and paragliding high in the sky.", + "price": 0.29, + "scariness": 4 + } +] \ No newline at end of file diff --git a/app/src/main/java/com/anelcc/monster/MainViewModel.kt b/app/src/main/java/com/anelcc/monster/MainViewModel.kt index e9ef469..e8ec30a 100644 --- a/app/src/main/java/com/anelcc/monster/MainViewModel.kt +++ b/app/src/main/java/com/anelcc/monster/MainViewModel.kt @@ -9,7 +9,11 @@ import com.anelcc.monster.utilities.FileHelper class MainViewModel(app: Application) : AndroidViewModel(app) { // TODO: Implement the ViewModel init { - val text = FileHelper.getTextFromResources(app, R.raw.monster_data) - Log.i(LOG_TAG, text) + val resourcesText = FileHelper.getTextFromResources(app, R.raw.monster_data) + Log.i(LOG_TAG, "Resources: $resourcesText") + + + val assetsText = FileHelper.getTextFromAssets(app, "monster_data.json") + Log.i(LOG_TAG, "Assets: $assetsText") } } diff --git a/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt b/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt index acf751e..948a4e0 100644 --- a/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt +++ b/app/src/main/java/com/anelcc/monster/utilities/FileHelper.kt @@ -5,6 +5,7 @@ import android.content.Context class FileHelper { //In java you create Static methods in Kotlin you function member of the companions companion object { + fun getTextFromResources(context: Context, resourceId: Int): String { return context.resources.openRawResource(resourceId).use { it.bufferedReader().use { @@ -12,5 +13,13 @@ class FileHelper { } } } + + fun getTextFromAssets(context: Context, fileName: String): String { + return context.assets.open(fileName).use { + it.bufferedReader().use { + it.readText() + } + } + } } } \ No newline at end of file From 195b7da50a63c36531acff2aa47259ac230200b7 Mon Sep 17 00:00:00 2001 From: Anel CC Date: Sun, 12 Apr 2020 14:10:31 -0400 Subject: [PATCH 6/9] [Anel] Parse JSON strings with Moshi --- app/build.gradle | 8 ++++++- .../java/com/anelcc/monster/MainViewModel.kt | 24 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3167881..7a760a0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,8 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' + android { compileSdkVersion 29 buildToolsVersion "29.0.2" @@ -44,5 +46,9 @@ dependencies { // This container view models and data - implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + + // This container view models and data + implementation 'com.squareup.moshi:moshi-kotlin:1.9.2' + kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.9.2' } diff --git a/app/src/main/java/com/anelcc/monster/MainViewModel.kt b/app/src/main/java/com/anelcc/monster/MainViewModel.kt index e8ec30a..8627c5c 100644 --- a/app/src/main/java/com/anelcc/monster/MainViewModel.kt +++ b/app/src/main/java/com/anelcc/monster/MainViewModel.kt @@ -3,11 +3,20 @@ package com.anelcc.monster import android.app.Application import android.util.Log import androidx.lifecycle.AndroidViewModel +import com.anelcc.monster.data.Monster import com.anelcc.monster.utilities.FileHelper +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Moshi +import com.squareup.moshi.Types +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory class MainViewModel(app: Application) : AndroidViewModel(app) { - // TODO: Implement the ViewModel + + private val listType = Types.newParameterizedType( + List::class.java, Monster::class.java + ) + init { val resourcesText = FileHelper.getTextFromResources(app, R.raw.monster_data) Log.i(LOG_TAG, "Resources: $resourcesText") @@ -15,5 +24,18 @@ class MainViewModel(app: Application) : AndroidViewModel(app) { val assetsText = FileHelper.getTextFromAssets(app, "monster_data.json") Log.i(LOG_TAG, "Assets: $assetsText") + + parseText(assetsText) + } + + fun parseText(text: String) { + val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + val adapter: JsonAdapter> = moshi.adapter(listType) + //This is parsing the data + val monsterData = adapter.fromJson(text) + + for (monster in monsterData ?: emptyList()) { + Log.i(LOG_TAG,"parseText: ${monster.monsterName} (\$${monster.price})") + } } } From 7569fb341df34179440881c46073436d4ff109dd Mon Sep 17 00:00:00 2001 From: Anel CC Date: Mon, 13 Apr 2020 18:22:40 -0400 Subject: [PATCH 7/9] [Anel] Map JSON and class property names --- app/src/main/java/com/anelcc/monster/MainViewModel.kt | 2 +- app/src/main/java/com/anelcc/monster/data/Monster.kt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/anelcc/monster/MainViewModel.kt b/app/src/main/java/com/anelcc/monster/MainViewModel.kt index 8627c5c..f6071ee 100644 --- a/app/src/main/java/com/anelcc/monster/MainViewModel.kt +++ b/app/src/main/java/com/anelcc/monster/MainViewModel.kt @@ -35,7 +35,7 @@ class MainViewModel(app: Application) : AndroidViewModel(app) { val monsterData = adapter.fromJson(text) for (monster in monsterData ?: emptyList()) { - Log.i(LOG_TAG,"parseText: ${monster.monsterName} (\$${monster.price})") + Log.i(LOG_TAG,"parseText: ${monster.name} (\$${monster.price})") } } } diff --git a/app/src/main/java/com/anelcc/monster/data/Monster.kt b/app/src/main/java/com/anelcc/monster/data/Monster.kt index 510b540..727a983 100644 --- a/app/src/main/java/com/anelcc/monster/data/Monster.kt +++ b/app/src/main/java/com/anelcc/monster/data/Monster.kt @@ -1,7 +1,10 @@ package com.anelcc.monster.data +import com.squareup.moshi.Json + data class Monster ( - val monsterName: String, + @Json(name = "monsterName") + val name: String, val imageFile: String, val caption: String, val description: String, From e6dfa98acc2fed52f5bb71bfe2264024a73647af Mon Sep 17 00:00:00 2001 From: Anel CC Date: Tue, 14 Apr 2020 17:42:23 -0400 Subject: [PATCH 8/9] resolve coments from review --- .idea/codeStyles/Project.xml | 3 --- .idea/gradle.xml | 4 +++- .idea/misc.xml | 2 +- app/build.gradle | 1 - app/src/main/java/com/anelcc/monster/MainViewModel.kt | 2 -- app/src/main/java/com/anelcc/monster/main/MainFragment.kt | 2 -- 6 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 45b5654..88ea3aa 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,8 +1,5 @@ - - diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 169fd0d..674414f 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,8 +1,11 @@ + diff --git a/.idea/misc.xml b/.idea/misc.xml index 37a7509..7bfef59 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/app/build.gradle b/app/build.gradle index 7a760a0..f1048ce 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,7 +44,6 @@ dependencies { implementation 'androidx.core:core-ktx:1.0.1' implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" - // This container view models and data implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' diff --git a/app/src/main/java/com/anelcc/monster/MainViewModel.kt b/app/src/main/java/com/anelcc/monster/MainViewModel.kt index f6071ee..740be75 100644 --- a/app/src/main/java/com/anelcc/monster/MainViewModel.kt +++ b/app/src/main/java/com/anelcc/monster/MainViewModel.kt @@ -10,7 +10,6 @@ import com.squareup.moshi.Moshi import com.squareup.moshi.Types import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory - class MainViewModel(app: Application) : AndroidViewModel(app) { private val listType = Types.newParameterizedType( @@ -21,7 +20,6 @@ class MainViewModel(app: Application) : AndroidViewModel(app) { val resourcesText = FileHelper.getTextFromResources(app, R.raw.monster_data) Log.i(LOG_TAG, "Resources: $resourcesText") - val assetsText = FileHelper.getTextFromAssets(app, "monster_data.json") Log.i(LOG_TAG, "Assets: $assetsText") diff --git a/app/src/main/java/com/anelcc/monster/main/MainFragment.kt b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt index a97bf6f..e615b7e 100644 --- a/app/src/main/java/com/anelcc/monster/main/MainFragment.kt +++ b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt @@ -15,7 +15,6 @@ import com.anelcc.monster.data.Monster class MainFragment : Fragment() { - companion object { fun newInstance() = MainFragment() } @@ -39,5 +38,4 @@ class MainFragment : Fragment() { viewModel = ViewModelProvider(this).get(MainViewModel::class.java) // TODO: Use the ViewModel } - } From ab0b37c91da85c05322bb68250d9eb45506e265c Mon Sep 17 00:00:00 2001 From: Anel CC Date: Tue, 14 Apr 2020 17:48:05 -0400 Subject: [PATCH 9/9] resolve coments from review one line --- app/src/main/java/com/anelcc/monster/main/MainFragment.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/anelcc/monster/main/MainFragment.kt b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt index e615b7e..2505cf8 100644 --- a/app/src/main/java/com/anelcc/monster/main/MainFragment.kt +++ b/app/src/main/java/com/anelcc/monster/main/MainFragment.kt @@ -26,8 +26,7 @@ class MainFragment : Fragment() { savedInstanceState: Bundle? ): View { - val monster = Monster("Bob", "myfile", "a caption", - "a description", .19, 3) + val monster = Monster("Bob", "myfile", "a caption", "a description", .19, 3) Log.i("monsterLogging", monster.toString()) return inflater.inflate(R.layout.fragment_main, container, false)