mirror of
https://github.com/hmalik144/Android-developer-tech-test---POQ.git
synced 2025-12-10 03:05:24 +00:00
New commit with added features:
- filter list - new list item layout
This commit is contained in:
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -8,7 +8,7 @@ android {
|
||||
compileSdkVersion 28
|
||||
defaultConfig {
|
||||
applicationId "com.example.h_mal.myapplication"
|
||||
minSdkVersion 15
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
@@ -33,4 +33,5 @@ dependencies {
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.2.1'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
androidTestImplementation 'com.android.support.test:rules:1.0.2'
|
||||
implementation 'com.android.support:cardview-v7:28.0.0'
|
||||
}
|
||||
|
||||
@@ -1,28 +1,86 @@
|
||||
package com.example.h_mal.myapplication
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.net.UrlQuerySanitizer
|
||||
import android.opengl.Visibility
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Filter
|
||||
import com.example.h_mal.myapplication.model.JsonObject
|
||||
import kotlinx.android.synthetic.main.repo_list_item.view.*
|
||||
|
||||
//custom list adapter extends from array adater
|
||||
class ListViewAdapter(context: Context, objects: MutableList<JsonObject>) :
|
||||
ArrayAdapter<JsonObject>(context, 0, objects){
|
||||
|
||||
//populate each view
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
//if the current view is null then inflate our list item object into list
|
||||
var view: View? = convertView
|
||||
if (view == null) {
|
||||
view = LayoutInflater.from(context).inflate(R.layout.repo_list_item, parent, false)
|
||||
view = LayoutInflater.from(context).inflate(R.layout.repo_list_item, parent, false)!!
|
||||
}
|
||||
|
||||
//get the current item from the current position
|
||||
val item = getItem(position)
|
||||
|
||||
view?.name?.text = item?.name
|
||||
view?.description?.text = item?.description
|
||||
//set name and description
|
||||
view.name?.text = item?.name
|
||||
view.description?.text = item?.description
|
||||
|
||||
//parse date from the date time string and set the date
|
||||
val dateString = item?.date?.split('T')?.get(0)
|
||||
view.date?.text = dateString
|
||||
|
||||
return view!!
|
||||
//check if the language object is null
|
||||
if (item.language != null){
|
||||
//language exists in object
|
||||
//view holdin the language to be visible
|
||||
view.lang_layout.visibility = View.VISIBLE
|
||||
|
||||
//language text and corresponding colour according to github is applied
|
||||
view.lang?.text = item.language
|
||||
getColor(item.language)?.let { it1 -> view.lang_col.setCardBackgroundColor(it1) }
|
||||
}else{
|
||||
//language was null therefore view to be hidden
|
||||
view.lang_layout.visibility = View.GONE
|
||||
}
|
||||
|
||||
//apply on click listener to item
|
||||
view.setOnClickListener{
|
||||
//click item opens then url
|
||||
openLink(item.repoUrlString)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
//function for opening the link
|
||||
fun openLink(urlString : String?){
|
||||
//open link to repo if the url is not nu;;
|
||||
if (urlString != null){
|
||||
val openURL = Intent(Intent.ACTION_VIEW)
|
||||
openURL.data = Uri.parse(urlString)
|
||||
context.startActivity(openURL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//get the corresponding colour based on the programming language
|
||||
fun getColor(language: String?) : Int?{
|
||||
return when(language) {
|
||||
"Ruby" -> context.getColor(R.color.Ruby)
|
||||
"Java"-> context.getColor(R.color.Java)
|
||||
"Objective-C" -> context.getColor(R.color.ObjectiveC)
|
||||
"JavaScript" -> context.getColor(R.color.JavaScript)
|
||||
"CSS" -> context.getColor(R.color.CSS)
|
||||
"Shell" -> context.getColor(R.color.Shell)
|
||||
//if the language has no match return nothing
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,10 @@ import android.content.Context
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.support.v4.widget.SwipeRefreshLayout
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.SearchView
|
||||
import com.example.h_mal.myapplication.model.JsonObject
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
@@ -12,49 +16,101 @@ import java.io.IOException
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
lateinit var thecontext: Context
|
||||
lateinit var searchView: SearchView
|
||||
|
||||
companion object{
|
||||
val urlString = "https://api.github.com/orgs/square/repos"
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
thecontext = this
|
||||
|
||||
//begin populating list
|
||||
executeTask()
|
||||
|
||||
//set a listener for the swipe to refresh
|
||||
swipe_refresh.setOnRefreshListener(swipeRefreshListener)
|
||||
}
|
||||
|
||||
//implement search interface in the menu
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
//inflate custom menu as our menu
|
||||
menuInflater.inflate(R.menu.menu, menu)
|
||||
//extract searchview
|
||||
val searchItem = menu?.findItem(R.id.search)
|
||||
//set searchview globally
|
||||
searchView = searchItem?.actionView as SearchView
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
val swipeRefreshListener = SwipeRefreshLayout.OnRefreshListener{
|
||||
//populate list when pulling to refresh
|
||||
executeTask()
|
||||
}
|
||||
|
||||
fun executeTask(){
|
||||
//clear list before populating
|
||||
list_view.adapter = null
|
||||
|
||||
//create url from url string urlstring
|
||||
val url = Request.Builder().url(urlString).build()
|
||||
//create a okhttpclient for a get request from url
|
||||
val client = OkHttpClient()
|
||||
|
||||
//call the url and retrieve its callback
|
||||
client.newCall(url).enqueue(object: Callback {
|
||||
//failure of retrieval callback
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
//print error to log
|
||||
System.err.println(e)
|
||||
|
||||
//if swipe refresh is refreshing then stop
|
||||
swipe_refresh.isRefreshing = false
|
||||
//list is empty
|
||||
}
|
||||
|
||||
//successful retrieval callback
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
//get the JSON from the body
|
||||
val urlResponse = response.body?.string()
|
||||
|
||||
//print the response to the logs
|
||||
println("response = $urlResponse")
|
||||
|
||||
//create gson object
|
||||
val gson = Gson()
|
||||
//create a mutable list of objects extracted from the json text
|
||||
val objectList = gson.fromJson(urlResponse, Array<JsonObject>::class.java).asList().toMutableList()
|
||||
|
||||
if (objectList.size >0){
|
||||
//update the ui
|
||||
runOnUiThread{
|
||||
list_view.adapter = ListViewAdapter(thecontext, objectList)
|
||||
//custom list view adapter created
|
||||
val adapterLV = ListViewAdapter(baseContext, objectList)
|
||||
//apply adapter to listview
|
||||
list_view.adapter = adapterLV
|
||||
//if swipe refresh is refreshing then stop
|
||||
swipe_refresh.isRefreshing = false
|
||||
|
||||
//search view has its query change listener applied
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
|
||||
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//as the test is changed the list is filtered
|
||||
override fun onQueryTextChange(newText: String?): Boolean {
|
||||
//filter list function
|
||||
adapterLV.filter.filter(newText)
|
||||
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
}else{
|
||||
//list is empty
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ data class JsonObject(
|
||||
var description : String? = null,
|
||||
@SerializedName("language")
|
||||
var language : String? = null,
|
||||
@SerializedName("created_at")
|
||||
var date : String? = null,
|
||||
@SerializedName("html_url")
|
||||
var repoUrlString : String? = null
|
||||
)
|
||||
|
||||
9
app/src/main/res/drawable/ic_search_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_search_black_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/ic_search_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_search_white_24dp.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/ic_sort_black_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_sort_black_24dp.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
|
||||
</vector>
|
||||
@@ -19,4 +19,6 @@
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
@@ -1,18 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<TextView
|
||||
android:hint="name"
|
||||
android:layout_margin="12dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" tools:layout_editor_absoluteY="16dp"
|
||||
tools:layout_editor_absoluteX="16dp" android:id="@+id/name"/>
|
||||
<TextView
|
||||
android:hint="description"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_below="@id/name"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
app:cardCornerRadius="12dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="3"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#30ABC5"
|
||||
tools:text="Name of repo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1"
|
||||
tools:text="19/04/2018" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:backgroundTint="#30ABC5"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" tools:layout_editor_absoluteY="44dp"
|
||||
tools:layout_editor_absoluteX="16dp" android:id="@+id/description"/>
|
||||
</RelativeLayout>
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="2dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="18sp"
|
||||
tools:text="Multi line description, text and more text then text
|
||||
add more text more of a description. Multi line
|
||||
description, text and more text then text add
|
||||
more text more of a description." />
|
||||
|
||||
<LinearLayout android:id="@+id/lang_layout" android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp" android:gravity="right">
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="match_parent"
|
||||
tools:text="Java" android:gravity="center" android:id="@+id/lang"/>
|
||||
<android.support.v7.widget.CardView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
app:cardCornerRadius="8dp" app:cardBackgroundColor="#E03F3F" android:id="@+id/lang_col"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
</FrameLayout>
|
||||
7
app/src/main/res/menu/menu.xml
Normal file
7
app/src/main/res/menu/menu.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/search"
|
||||
android:title="@string/search_title"
|
||||
android:icon="@drawable/ic_search_white_24dp"
|
||||
app:showAsAction="collapseActionView|ifRoom" app:actionViewClass="android.widget.SearchView"/>
|
||||
</menu>
|
||||
@@ -1,6 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorPrimary">#30ABC5</color>
|
||||
<color name="colorPrimaryDark">#247E91</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
|
||||
<color name="Ruby">#701516</color>
|
||||
<color name="Java">#b07219</color>
|
||||
<color name="ObjectiveC">#438eff</color>
|
||||
<color name="JavaScript">#f1e05a</color>
|
||||
<color name="CSS">#563d7c</color>
|
||||
<color name="Shell">#89e051</color>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
<resources>
|
||||
<string name="app_name">SquareGithubRepo</string>
|
||||
<string name="search_title">Search</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user