diff --git a/.idea/misc.xml b/.idea/misc.xml
index d5727af..3484bf1 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -8,7 +8,7 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 56806ce..c8f3947 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -30,8 +30,11 @@ dependencies {
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 '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'
+ implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
+ implementation 'com.squareup.retrofit2:retrofit:2.3.0'
+ implementation 'io.reactivex.rxjava2:rxjava:2.1.9'
+ implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
}
diff --git a/app/src/androidTest/java/com/example/h_mal/myapplication/MainActivityTest.kt b/app/src/androidTest/java/com/example/h_mal/myapplication/MainActivityTest.kt
index 5eb92e6..ffe12c7 100644
--- a/app/src/androidTest/java/com/example/h_mal/myapplication/MainActivityTest.kt
+++ b/app/src/androidTest/java/com/example/h_mal/myapplication/MainActivityTest.kt
@@ -2,28 +2,22 @@ package com.example.h_mal.myapplication
import android.support.test.espresso.Espresso
-import android.support.test.espresso.Espresso.*
-import android.support.test.espresso.action.ViewActions.click
-import android.support.test.espresso.matcher.ViewMatchers.withId
+import android.support.test.espresso.Espresso.onView
+import android.support.test.espresso.assertion.ViewAssertions.matches
+import android.support.test.espresso.matcher.ViewMatchers.*
import android.support.test.filters.LargeTest
import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
import android.view.View
import android.view.ViewGroup
+import com.example.h_mal.myapplication.ui.MainActivity
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.Matchers.allOf
-import org.hamcrest.Matchers.anything
import org.hamcrest.TypeSafeMatcher
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import android.support.test.espresso.UiController
-import android.support.test.orchestrator.junit.BundleJUnitUtils.getDescription
-import android.support.test.espresso.ViewAction
-import android.support.test.espresso.action.ViewActions.swipeDown
-import android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast
-
@LargeTest
@RunWith(AndroidJUnit4::class)
@@ -36,24 +30,6 @@ class MainActivityTest {
@Test
fun mainActivityTest() {
- onIdle()
-
-
- val relativeLayout = onData(anything())
- .inAdapterView(
- allOf(
- withId(R.id.list_view),
- childAtPosition(
- withId(R.id.swipe_refresh),
- 0
- )
- )
- )
- .atPosition(0)
- relativeLayout.perform(click())
-
- onView(withId(R.id.swipe_refresh))
- .perform(withCustomConstraints(swipeDown(), isDisplayingAtLeast(85)))
}
private fun childAtPosition(
@@ -73,20 +49,4 @@ class MainActivityTest {
}
}
}
-
- fun withCustomConstraints(action: ViewAction, constraints: Matcher): ViewAction {
- return object : ViewAction {
- override fun getConstraints(): Matcher {
- return constraints
- }
-
- override fun getDescription(): String {
- return action.description
- }
-
- override fun perform(uiController: UiController, view: View) {
- action.perform(uiController, view)
- }
- }
- }
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b7dc53e..64c7128 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,7 +12,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
-
+
diff --git a/app/src/main/java/com/example/h_mal/myapplication/Api/GetData.kt b/app/src/main/java/com/example/h_mal/myapplication/Api/GetData.kt
new file mode 100644
index 0000000..f6cbb85
--- /dev/null
+++ b/app/src/main/java/com/example/h_mal/myapplication/Api/GetData.kt
@@ -0,0 +1,11 @@
+package com.example.h_mal.myapplication.Api
+
+import com.example.h_mal.myapplication.model.Repo
+import io.reactivex.Observable
+import retrofit2.http.GET
+
+interface GetData{
+
+ @GET("repos")
+ fun getData() : Observable>
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/h_mal/myapplication/MainActivity.kt b/app/src/main/java/com/example/h_mal/myapplication/MainActivity.kt
deleted file mode 100644
index 5ed2182..0000000
--- a/app/src/main/java/com/example/h_mal/myapplication/MainActivity.kt
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.example.h_mal.myapplication
-
-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.*
-import okhttp3.*
-import java.io.IOException
-
-
-class MainActivity : AppCompatActivity() {
- lateinit var searchView: SearchView
-
- val urlString = "https://api.github.com/orgs/square/repos"
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
-
- //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::class.java).asList().toMutableList()
-
- if (objectList.size >0){
- //update the ui
- runOnUiThread{
- //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
- }
-
- }
- })
- }
-
-
-}
diff --git a/app/src/main/java/com/example/h_mal/myapplication/model/JsonObject.kt b/app/src/main/java/com/example/h_mal/myapplication/model/Repo.kt
similarity index 50%
rename from app/src/main/java/com/example/h_mal/myapplication/model/JsonObject.kt
rename to app/src/main/java/com/example/h_mal/myapplication/model/Repo.kt
index 782fad6..bb11b0f 100644
--- a/app/src/main/java/com/example/h_mal/myapplication/model/JsonObject.kt
+++ b/app/src/main/java/com/example/h_mal/myapplication/model/Repo.kt
@@ -2,15 +2,9 @@ package com.example.h_mal.myapplication.model
import com.google.gson.annotations.SerializedName
-data class JsonObject(
- @SerializedName("name")
+data class Repo(
var name: String? = null,
- @SerializedName("description")
var description : String? = null,
- @SerializedName("language")
var language : String? = null,
- @SerializedName("created_at")
var date : String? = null,
- @SerializedName("html_url")
- var repoUrlString : String? = null
-)
+ var html_url : String? = null)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/h_mal/myapplication/ListViewAdapter.kt b/app/src/main/java/com/example/h_mal/myapplication/ui/ListViewAdapter.kt
similarity index 78%
rename from app/src/main/java/com/example/h_mal/myapplication/ListViewAdapter.kt
rename to app/src/main/java/com/example/h_mal/myapplication/ui/ListViewAdapter.kt
index 2c15217..ef4a95e 100644
--- a/app/src/main/java/com/example/h_mal/myapplication/ListViewAdapter.kt
+++ b/app/src/main/java/com/example/h_mal/myapplication/ui/ListViewAdapter.kt
@@ -1,21 +1,20 @@
-package com.example.h_mal.myapplication
+package com.example.h_mal.myapplication.ui
import android.content.Context
import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
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 com.example.h_mal.myapplication.R
+import com.example.h_mal.myapplication.model.Repo
import kotlinx.android.synthetic.main.repo_list_item.view.*
//custom list adapter extends from array adater
-class ListViewAdapter(context: Context, objects: MutableList) :
- ArrayAdapter(context, 0, objects){
+class ListViewAdapter(context: Context, objects: MutableList) :
+ ArrayAdapter(context, 0, objects){
//populate each view
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
@@ -36,8 +35,15 @@ class ListViewAdapter(context: Context, objects: MutableList) :
val dateString = item?.date?.split('T')?.get(0)
view.date?.text = dateString
+ //control the language section of the view
+ populateLanguage(item, view)
+
+ return view
+ }
+
+ fun populateLanguage(item : Repo?, view : View){
//check if the language object is null
- if (item.language != null){
+ if (item?.language != null){
//language exists in object
//view holdin the language to be visible
view.lang_layout.visibility = View.VISIBLE
@@ -49,25 +55,6 @@ class ListViewAdapter(context: Context, objects: MutableList) :
//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
@@ -83,4 +70,19 @@ class ListViewAdapter(context: Context, objects: MutableList) :
else -> null
}
}
+
+ //function for opening the link
+ fun openLink(position: Int){
+ val urlString = getItem(position)?.html_url
+ //open link to repo if the url is not null
+ if (urlString != null){
+ val openURL = Intent(Intent.ACTION_VIEW)
+ openURL.addFlags(FLAG_ACTIVITY_NEW_TASK)
+ openURL.data = Uri.parse(urlString)
+ context.startActivity(openURL)
+ }
+
+ }
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/h_mal/myapplication/ui/MainActivity.kt b/app/src/main/java/com/example/h_mal/myapplication/ui/MainActivity.kt
new file mode 100644
index 0000000..b62603f
--- /dev/null
+++ b/app/src/main/java/com/example/h_mal/myapplication/ui/MainActivity.kt
@@ -0,0 +1,144 @@
+package com.example.h_mal.myapplication.ui
+
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import android.support.v4.widget.SwipeRefreshLayout
+import android.view.Menu
+import android.view.View
+import android.widget.SearchView
+import com.example.h_mal.myapplication.Api.GetData
+import com.example.h_mal.myapplication.R
+import com.example.h_mal.myapplication.model.Repo
+import kotlinx.android.synthetic.main.activity_main.*
+import io.reactivex.disposables.CompositeDisposable
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
+import retrofit2.Retrofit
+
+import io.reactivex.schedulers.Schedulers
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.observers.DisposableObserver
+
+
+class MainActivity : AppCompatActivity() {
+ lateinit var searchView: SearchView
+ lateinit var myCompositeDisposable: CompositeDisposable
+
+ val urlString = "https://api.github.com/orgs/square/"
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ spinner.visibility = View.VISIBLE
+
+ myCompositeDisposable = CompositeDisposable()
+
+ //begin populating list
+ loadData()
+
+ //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
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+
+ myCompositeDisposable?.clear()
+ }
+
+ val swipeRefreshListener = SwipeRefreshLayout.OnRefreshListener{
+ //populate list when pulling to refresh
+// callData()
+ loadData()
+ }
+
+ fun loadData(){
+ //clear list before populating
+ list_view.adapter = null
+
+ val requestInterface = Retrofit.Builder()
+ .baseUrl(urlString)
+ .addConverterFactory(GsonConverterFactory.create())
+ .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+ .build().create(GetData::class.java)
+
+ myCompositeDisposable.add(requestInterface.getData()
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver>() {
+ override fun onNext(t: List) {
+ handleResponse(t)
+ }
+
+ override fun onComplete() {
+
+ }
+
+ override fun onError(e: Throwable) {
+ handleError()
+ }
+ }))
+ }
+
+ private fun handleResponse(objectList: List) {
+
+ spinner.visibility = View.GONE
+
+ //if swipe refresh is refreshing then stop
+ swipe_refresh.isRefreshing = false
+
+ if (objectList.isNotEmpty()){
+ //list is not empty
+ empty_view.visibility = View.GONE
+ //custom list view adapter created
+ val adapterLV = ListViewAdapter(baseContext, objectList.toMutableList())
+ //apply adapter to listview
+ list_view.adapter = adapterLV
+
+ list_view.setOnItemClickListener { parent, view, position, id ->
+ adapterLV.openLink(position)
+ }
+
+ //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
+ }
+ })
+ }
+
+ }
+
+ fun handleError(){
+ //if swipe refresh is refreshing then stop
+ swipe_refresh.isRefreshing = false
+ //list is empty
+ empty_view.visibility = View.VISIBLE
+ //progress bar hidden
+ spinner.visibility = View.GONE
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index e7668de..c6a1ef3 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -5,7 +5,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".MainActivity">
+ tools:context=".ui.MainActivity">
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/repo_list_item.xml b/app/src/main/res/layout/repo_list_item.xml
index 5ef36ef..04f1bef 100644
--- a/app/src/main/res/layout/repo_list_item.xml
+++ b/app/src/main/res/layout/repo_list_item.xml
@@ -66,12 +66,13 @@ more text more of a description." />
-