Skip to content

Commit

Permalink
Fix non-rectangle drag issue
Browse files Browse the repository at this point in the history
  • Loading branch information
Sdghasemi committed Jul 22, 2023
1 parent 7563ee2 commit 053c8ac
Show file tree
Hide file tree
Showing 37 changed files with 161 additions and 132 deletions.
44 changes: 37 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Peaks Assignment App
# Rectangles Custom View
This is a sample app using a fictional endpoint to retrieve rectangles properties and display them in a custom view.

Rectangles are placed around the screen based on their size and coordinates. User can drag them around the screen and update cached their position.

The app is written in pure Kotlin and is using Kotlin Gradle DSL for gradle scripts as well.

MainFragment is responsible for displaying the rectangles and enabling users to move them.
Expand All @@ -13,7 +15,8 @@ If there was an error retrieving data, a relevant message would inform the user
The application reaches the endpoint and caches the response. The cache expires after 1 week of inactivity.
When the cache is ready and valid (not expired) no endpoint call is made and the UI is populated purely with the cache itself.

The images displayed as thumbnails are also cached for better experience.
## Architecture
Built with MVVM clean code.

## Libraries
<ul>
Expand All @@ -22,12 +25,39 @@ The images displayed as thumbnails are also cached for better experience.
<li>Room for caching and Database manipulation</li>
</ul>

## Decisions
In order to draw rectangles, either using paint or declaring a drawable would do the job. Also the performance was almost the same.
I decided to use the drawable to enable the developer for better future changes and easier control over the shape of the rectangle.
## Testing
- #### Unit Testing
- Contains ViewModel tests with fake repository
- #### UI Testing
- Main fragment internet connectivity test and rectangles user interactions included

### API
```
GET /resourcer/v1/rectangles HTTP/1.1
The base API url of the endpoint was not clear from the assignment, so I asked Tjerk and turns out the API is fictional so
I decided to use "https://example.com/".
HTTP/1.1 200 OK
Content-Type: application/json
{
"rectangles": [
{
"x": 0.5,
"y": 0.5,
"size": 0.2
},
{
"x": 0.7,
"y": 0.7,
"size": 0.2
}
]
}
```
- `rectangles`: list of rectangles.
- `x` and `y`: position of the rectangle relative to the screen. E.g. x:0.5, y:0.5 means a
rectangle in the centre of the screen.
- `size`: the size of the rectangle in percentage relative to the screen. E.g. size:0.1
means a width of 10% of the width of the screen and a height of 10% of the height of
the screen.

### Contact developer

Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ android {
compileSdk = 32

defaultConfig {
applicationId = "com.hirno.assignment"
applicationId = "com.hirno.rectangles"
minSdk = 21
targetSdk = 32
versionCode = 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment
package com.hirno.rectangles

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
Expand All @@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.hirno.assignment", appContext.packageName)
assertEquals("com.hirno.rectangles", appContext.packageName)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.hirno.assignment.ui.main
package com.hirno.rectangles.ui.main

import com.hirno.assignment.data.GenericResponse
import com.hirno.assignment.data.source.RectanglesRepository
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.assignment.model.rectangle.RectanglesResponseModel
import com.hirno.assignment.network.response.NetworkResponse
import com.hirno.rectangles.data.GenericResponse
import com.hirno.rectangles.data.source.RectanglesRepository
import com.hirno.rectangles.model.rectangle.RectangleItemModel
import com.hirno.rectangles.model.rectangle.RectanglesResponseModel
import com.hirno.rectangles.network.response.NetworkResponse
import okio.IOException

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment.ui.main
package com.hirno.rectangles.ui.main

import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.test.espresso.Espresso.onView
Expand All @@ -7,9 +7,9 @@ import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.hirno.assignment.R
import com.hirno.assignment.ServiceLocator
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.rectangles.R
import com.hirno.rectangles.ServiceLocator
import com.hirno.rectangles.model.rectangle.RectangleItemModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.hamcrest.core.Is.`is`
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.hirno.assignment">
package="com.hirno.rectangles">

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

<application
android:name=".MainApplication"
android:name="com.hirno.rectangles.MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand All @@ -15,7 +15,7 @@
android:theme="@style/Theme.App"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name="com.hirno.rectangles.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.hirno.assignment
package com.hirno.rectangles

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.hirno.assignment.ui.main.MainFragment
import com.hirno.rectangles.ui.main.MainFragment

class MainActivity : AppCompatActivity() {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.hirno.assignment
package com.hirno.rectangles

import android.app.Application
import com.hirno.assignment.data.source.RectanglesRepository
import com.hirno.rectangles.data.source.RectanglesRepository

class MainApplication : Application() {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.hirno.assignment
package com.hirno.rectangles

import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.room.Room
import com.hirno.assignment.data.source.RectanglesDataSource
import com.hirno.assignment.data.source.RectanglesRepository
import com.hirno.assignment.data.source.DefaultRectanglesRepository
import com.hirno.assignment.data.source.local.AppDatabase
import com.hirno.assignment.data.source.local.RectanglesLocalDataSource
import com.hirno.assignment.data.source.remote.RectanglesRemoteDataSource
import com.hirno.rectangles.data.source.RectanglesDataSource
import com.hirno.rectangles.data.source.RectanglesRepository
import com.hirno.rectangles.data.source.DefaultRectanglesRepository
import com.hirno.rectangles.data.source.local.AppDatabase
import com.hirno.rectangles.data.source.local.RectanglesLocalDataSource
import com.hirno.rectangles.data.source.remote.RectanglesRemoteDataSource

/**
* A Service Locator for the [RectanglesRepository]. This is the prod version, with a
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment.data
package com.hirno.rectangles.data

import android.os.Parcelable
import com.google.gson.annotations.SerializedName
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.hirno.assignment.data
package com.hirno.rectangles.data

import com.hirno.assignment.network.response.NetworkResponse
import com.hirno.rectangles.network.response.NetworkResponse

/**
* A typealias used for using generic [ErrorResponseModel] as the ErrorModel type of [NetworkResponse]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.hirno.assignment.data.source
package com.hirno.rectangles.data.source

import android.content.Context
import com.hirno.assignment.data.GenericResponse
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.assignment.model.rectangle.RectanglesResponseModel
import com.hirno.assignment.network.response.NetworkResponse
import kotlinx.coroutines.delay
import com.hirno.rectangles.data.GenericResponse
import com.hirno.rectangles.model.rectangle.RectangleItemModel
import com.hirno.rectangles.model.rectangle.RectanglesResponseModel
import com.hirno.rectangles.network.response.NetworkResponse

/**
* Concrete implementation to load rectangles from the data sources into a cache.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.hirno.assignment.data.source
package com.hirno.rectangles.data.source

import com.hirno.assignment.model.rectangle.RectanglesResponseModel
import com.hirno.assignment.data.GenericResponse
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.rectangles.model.rectangle.RectanglesResponseModel
import com.hirno.rectangles.data.GenericResponse
import com.hirno.rectangles.model.rectangle.RectangleItemModel

/**
* Main entry point for accessing rectangles data.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.hirno.assignment.data.source
package com.hirno.rectangles.data.source

import com.hirno.assignment.data.GenericResponse
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.assignment.model.rectangle.RectanglesResponseModel
import com.hirno.rectangles.data.GenericResponse
import com.hirno.rectangles.model.rectangle.RectangleItemModel
import com.hirno.rectangles.model.rectangle.RectanglesResponseModel

/**
* Interface to the data layer.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.hirno.assignment.data.source.local
package com.hirno.rectangles.data.source.local

import androidx.room.Database
import androidx.room.RoomDatabase
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.rectangles.model.rectangle.RectangleItemModel

/**
* The Room Database that contains the Rectangles table.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.hirno.assignment.data.source.local
package com.hirno.rectangles.data.source.local

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.rectangles.model.rectangle.RectangleItemModel

/**
* Data Access Object for Rectangles table
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.hirno.assignment.data.source.local
package com.hirno.rectangles.data.source.local

import com.hirno.assignment.data.source.RectanglesDataSource
import com.hirno.assignment.model.rectangle.RectanglesResponseModel
import com.hirno.assignment.data.GenericResponse
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.assignment.network.response.NetworkResponse
import com.hirno.rectangles.data.source.RectanglesDataSource
import com.hirno.rectangles.model.rectangle.RectanglesResponseModel
import com.hirno.rectangles.data.GenericResponse
import com.hirno.rectangles.model.rectangle.RectangleItemModel
import com.hirno.rectangles.network.response.NetworkResponse
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.hirno.assignment.data.source.remote
package com.hirno.rectangles.data.source.remote

import com.hirno.assignment.data.source.RectanglesDataSource
import com.hirno.assignment.model.rectangle.RectanglesResponseModel
import com.hirno.assignment.data.GenericResponse
import com.hirno.assignment.model.rectangle.RectangleItemModel
import com.hirno.assignment.network.ApiClient
import com.hirno.assignment.network.response.NetworkResponse
import kotlinx.coroutines.delay
import com.hirno.rectangles.data.source.RectanglesDataSource
import com.hirno.rectangles.model.rectangle.RectanglesResponseModel
import com.hirno.rectangles.data.GenericResponse
import com.hirno.rectangles.model.rectangle.RectangleItemModel
import com.hirno.rectangles.network.response.NetworkResponse

/**
* Rectangles remote data source implementation
Expand All @@ -22,17 +20,23 @@ object RectanglesRemoteDataSource : RectanglesDataSource {
return NetworkResponse.Success(RectanglesResponseModel(
rectangles = arrayListOf(
RectangleItemModel(
id = 513,
x = 0.5f,
id = 1,
x = 0.3f,
y = 0.5f,
size = 0.2f
),
RectangleItemModel(
id = 3,
id = 2,
x = 0.7f,
y = 0.7f,
size = 0.2f
)
size = 0.4f
),
RectangleItemModel(
id = 3,
x = 0.6f,
y = 0.2f,
size = 0.3f
),
)
))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment.model.rectangle
package com.hirno.rectangles.model.rectangle

import android.os.Parcelable
import androidx.room.ColumnInfo
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.hirno.assignment.network
package com.hirno.rectangles.network

import com.hirno.assignment.BuildConfig
import com.hirno.assignment.network.response.NetworkResponseAdapterFactory
import com.hirno.rectangles.BuildConfig
import com.hirno.rectangles.network.response.NetworkResponseAdapterFactory
import okhttp3.*
import okhttp3.internal.immutableListOf
import okhttp3.logging.HttpLoggingInterceptor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.hirno.assignment.network
package com.hirno.rectangles.network

import com.hirno.assignment.model.rectangle.RectanglesResponseModel
import com.hirno.assignment.data.GenericResponse
import com.hirno.rectangles.model.rectangle.RectanglesResponseModel
import com.hirno.rectangles.data.GenericResponse
import retrofit2.http.GET
import retrofit2.http.Query

/**
* API interface of the app endpoints
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment.network.response
package com.hirno.rectangles.network.response

import okio.IOException

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment.network.response
package com.hirno.rectangles.network.response

import okhttp3.ResponseBody
import retrofit2.Call
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment.network.response
package com.hirno.rectangles.network.response

import retrofit2.Call
import retrofit2.CallAdapter
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hirno.assignment.network.response
package com.hirno.rectangles.network.response

import okhttp3.Request
import okhttp3.ResponseBody
Expand Down
Loading

0 comments on commit 053c8ac

Please sign in to comment.