Skip to content

Commit 3494516

Browse files
author
Istvan Szollosi
committed
Merge branch 'master' into feature/search_page
2 parents 106001f + 66fb126 commit 3494516

40 files changed

+804
-147
lines changed

‎app/build.gradle‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ dependencies {
4242
implementation 'androidx.core:core-ktx:1.7.0'
4343
implementation 'androidx.appcompat:appcompat:1.4.1'
4444
implementation 'com.google.android.material:material:1.6.0'
45+
implementation 'io.github.inflationx:calligraphy3:3.1.1'
46+
implementation 'io.github.inflationx:viewpump:2.0.3'
4547

4648
implementation liveDataLifecycle
47-
implementation coil
49+
implementation glide
4850
implementation lottie
4951
implementation googleMaps
5052
implementation location
45.5 KB
Binary file not shown.
44.6 KB
Binary file not shown.

‎app/src/main/java/com/accenture/beecycle/BeeCycleApplication.kt‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package com.accenture.beecycle
33
import android.app.Application
44
import com.accenture.beecycle.data.di.*
55
import com.accenture.beecycle.di.viewModelModules
6+
import io.github.inflationx.calligraphy3.CalligraphyConfig
7+
import io.github.inflationx.calligraphy3.CalligraphyInterceptor
8+
import io.github.inflationx.viewpump.ViewPump
69
import kotlinx.coroutines.ExperimentalCoroutinesApi
710
import org.koin.android.ext.koin.androidContext
811
import org.koin.core.context.startKoin
@@ -13,6 +16,16 @@ class BeeCycleApplication : Application() {
1316
override fun onCreate() {
1417
super.onCreate()
1518

19+
ViewPump.init(ViewPump.builder()
20+
.addInterceptor(
21+
CalligraphyInterceptor(
22+
CalligraphyConfig.Builder()
23+
.setDefaultFontPath("abeezee_regular.ttf")
24+
.build())
25+
)
26+
.build()
27+
)
28+
1629
startKoin {
1730
androidContext(this@BeeCycleApplication)
1831
modules(listOf(

‎app/src/main/java/com/accenture/beecycle/common/BaseActivity.kt‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.accenture.beecycle.common
22

3+
import android.content.Context
34
import android.os.Bundle
45
import android.view.MenuItem
56
import androidx.appcompat.app.AlertDialog
67
import androidx.appcompat.app.AppCompatActivity
78
import androidx.viewbinding.ViewBinding
9+
import io.github.inflationx.viewpump.ViewPumpContextWrapper
10+
811

912
abstract class BaseActivity<V : ViewBinding, STATE : ViewState, INTENT : ViewIntent,
1013
ACTION : ViewAction, M : BaseViewModel<STATE, INTENT, ACTION>> : AppCompatActivity() {
@@ -31,6 +34,10 @@ abstract class BaseActivity<V : ViewBinding, STATE : ViewState, INTENT : ViewInt
3134
viewModel.state.observe(this) { render(it) }
3235
}
3336

37+
override fun attachBaseContext(newBase: Context) {
38+
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
39+
}
40+
3441
override fun onOptionsItemSelected(item: MenuItem): Boolean {
3542
if (item.itemId == android.R.id.home) {
3643
onBackPressed()

‎app/src/main/java/com/accenture/beecycle/di/ViewModelModules.kt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ import org.koin.dsl.module
88

99
@ExperimentalCoroutinesApi
1010
val viewModelModules = module {
11-
viewModel { MainViewModel(get()) }
11+
viewModel { MainViewModel(get(), get(), get()) }
1212
viewModel { SearchViewModel(get()) }
1313
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.accenture.beecycle.ui.main
2+
3+
import android.content.Intent
4+
import android.view.LayoutInflater
5+
import android.view.View
6+
import android.view.ViewGroup
7+
import androidx.core.view.isInvisible
8+
import androidx.core.view.isVisible
9+
import com.accenture.beecycle.R
10+
import com.accenture.beecycle.common.BaseAdapter
11+
import com.accenture.beecycle.databinding.ItemBicycleCardBinding
12+
import com.accenture.beecycle.domain.models.Bicycle
13+
import com.accenture.beecycle.domain.models.RIDE_TYPE
14+
import com.accenture.beecycle.ui.search.SearchActivity
15+
import kotlinx.coroutines.ExperimentalCoroutinesApi
16+
17+
@ExperimentalCoroutinesApi
18+
class BicycleAdapter : BaseAdapter<ItemBicycleCardBinding, Bicycle>() {
19+
20+
override fun presentBinding(parent: ViewGroup): ItemBicycleCardBinding =
21+
ItemBicycleCardBinding.inflate(
22+
LayoutInflater.from(parent.context),
23+
parent,
24+
false
25+
)
26+
27+
override fun onBindViewHolder(holder: ViewHolder<ItemBicycleCardBinding>, position: Int) {
28+
val bicycle = data?.get(position)
29+
with(holder.binding) {
30+
bicycleName.text = bicycle?.name
31+
bicycleBrand.text = bicycle?.brand
32+
bicycleSpeedValue.text = "${bicycle?.avgSpeed} km/h"
33+
bicycleDistanceValue.text = "${bicycle?.distanceTraveled} km"
34+
bicycleImpactValue.text = "${bicycle?.impact} CO2"
35+
bicycleMoneySaved.text = "You saved ${bicycle?.moneySaved}RON this week!"
36+
37+
bicycleAnimation.setAnimation(getRideAnimation(bicycle?.rideType))
38+
bicycleAnimation.playAnimation()
39+
40+
if (bicycle?.rideType == RIDE_TYPE.ADD_BIKE) {
41+
hideViews(bicycleName, bicycleBrand, bicycleSpeed, bicycleDistance, bicycleImpact, bicycleMoneySaved, bicycleAnimation, bicycleOpenRoutePlanner)
42+
showViews(bicycleAddBikeLabel, bicycleAddBikeAnimation)
43+
} else {
44+
showViews(bicycleName, bicycleBrand, bicycleSpeed, bicycleDistance, bicycleImpact, bicycleMoneySaved, bicycleAnimation, bicycleOpenRoutePlanner)
45+
hideViews(bicycleAddBikeLabel, bicycleAddBikeAnimation)
46+
47+
bicycleOpenRoutePlanner.setOnClickListener {
48+
val openSearch = Intent(root.context, SearchActivity::class.java)
49+
root.context.startActivity(openSearch)
50+
}
51+
}
52+
}
53+
}
54+
55+
private fun getRideAnimation(rideType: RIDE_TYPE?) : Int {
56+
return when(rideType) {
57+
RIDE_TYPE.BICYCLE -> R.raw.ic_cycling
58+
RIDE_TYPE.E_BICYCLE -> R.raw.ic_ebike
59+
RIDE_TYPE.E_SCOOTER -> R.raw.ic_electric_scooter
60+
else -> R.raw.ic_cycling
61+
}
62+
}
63+
64+
private fun hideViews(vararg view: View) {
65+
view.forEach { it.isInvisible = true }
66+
}
67+
68+
private fun showViews(vararg view: View) {
69+
view.forEach { it.isVisible = true }
70+
}
71+
}

‎app/src/main/java/com/accenture/beecycle/ui/main/MainAction.kt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ import com.accenture.beecycle.common.ViewAction
44

55
sealed class MainAction : ViewAction {
66
data class GetWeather(val latitude: Double?, val longitude: Double?): MainAction()
7+
object GetUserBicycles : MainAction()
8+
object GetUserTeams : MainAction()
79
}
Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,68 @@
11
package com.accenture.beecycle.ui.main
22

3-
import android.content.Intent
3+
import android.Manifest
4+
import android.content.pm.PackageManager
45
import android.os.Bundle
56
import android.view.LayoutInflater
7+
import android.widget.Toast
8+
import androidx.core.app.ActivityCompat
9+
import androidx.recyclerview.widget.LinearLayoutManager
610
import com.accenture.beecycle.common.BaseActivity
711
import com.accenture.beecycle.databinding.ActivityMainBinding
12+
import com.accenture.beecycle.domain.models.Bicycle
13+
import com.accenture.beecycle.domain.models.RIDE_TYPE
814
import com.accenture.beecycle.ui.search.SearchActivity
9-
import kotlinx.android.synthetic.main.item_bicycle_card.*
15+
import com.bumptech.glide.Glide
16+
import com.google.android.gms.location.FusedLocationProviderClient
17+
import com.google.android.gms.location.LocationServices
18+
import com.google.android.material.snackbar.Snackbar
19+
import com.google.android.material.tabs.TabLayoutMediator
20+
import kotlinx.android.synthetic.main.activity_main.*
21+
import kotlinx.android.synthetic.main.activity_search.*
1022
import kotlinx.coroutines.ExperimentalCoroutinesApi
1123
import org.koin.androidx.viewmodel.ext.android.viewModel
1224

25+
private const val REQ_LOCATION_PERMISSION = 0x1
26+
1327
@ExperimentalCoroutinesApi
1428
class MainActivity :
1529
BaseActivity<ActivityMainBinding, MainState, MainIntent, MainAction, MainViewModel>() {
1630

1731
override val viewModel: MainViewModel by viewModel()
1832

33+
private val bicycleAdapter = BicycleAdapter()
34+
private val teamAdapter = TeamAdapter()
35+
36+
private lateinit var locationClient: FusedLocationProviderClient
37+
1938
override fun onCreate(savedInstanceState: Bundle?) {
2039
super.onCreate(savedInstanceState)
2140

22-
dispatchIntent(MainIntent.GetCurrentWeather(40.7741391,-74.3084179))
23-
iv_start_search.setOnClickListener {
24-
val intent = Intent(this, SearchActivity::class.java)
25-
startActivity(intent)
41+
locationClient = LocationServices.getFusedLocationProviderClient(this)
42+
43+
listenToLocationChanges()
44+
setView()
45+
}
46+
47+
override fun onResume() {
48+
super.onResume()
49+
50+
dispatchIntent(MainIntent.GetUserBicycles)
51+
dispatchIntent(MainIntent.GetUserTeams)
52+
}
53+
54+
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
55+
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
56+
if (requestCode == REQ_LOCATION_PERMISSION) {
57+
if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
58+
Snackbar.make(
59+
this@MainActivity.main_container,
60+
"Permissions has been denied by user",
61+
Toast.LENGTH_SHORT
62+
).show()
63+
} else {
64+
listenToLocationChanges()
65+
}
2666
}
2767
}
2868

@@ -34,6 +74,46 @@ class MainActivity :
3474
MainState.LoadingWeather -> binding.mainWeather.loading()
3575
MainState.NoWeather -> binding.mainWeather.loading()
3676
is MainState.ResultWeather -> binding.mainWeather.setWeather(state.weather)
77+
is MainState.ResultUserBicycles -> bicycleAdapter.data = ArrayList(state.bicycles).apply {
78+
add(Bicycle(rideType = RIDE_TYPE.ADD_BIKE))
79+
}
80+
is MainState.ResultUserTeams -> teamAdapter.data = state.teams
81+
}
82+
}
83+
84+
private fun setView() {
85+
binding.mainBicycles.adapter = bicycleAdapter
86+
87+
binding.mainTeams.adapter = teamAdapter
88+
binding.mainTeams.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
89+
90+
Glide.with(this)
91+
.load("https://imagez.tmz.com/image/bf/4by3/2022/04/05/bf0bbec74a1a463f96cf1bacfa831049_md.jpg")
92+
.circleCrop()
93+
.into(binding.mainAvatar)
94+
95+
TabLayoutMediator(binding.mainBicyclesDots, binding.mainBicycles) { _, _ -> }.attach()
96+
}
97+
98+
private fun listenToLocationChanges() {
99+
if (ActivityCompat.checkSelfPermission(
100+
this,
101+
Manifest.permission.ACCESS_FINE_LOCATION
102+
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
103+
this,
104+
Manifest.permission.ACCESS_COARSE_LOCATION
105+
) != PackageManager.PERMISSION_GRANTED
106+
) {
107+
ActivityCompat.requestPermissions(
108+
this,
109+
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION),
110+
REQ_LOCATION_PERMISSION
111+
)
112+
return
37113
}
114+
locationClient.lastLocation
115+
.addOnSuccessListener(this) { location ->
116+
dispatchIntent(MainIntent.GetCurrentWeather(location?.latitude, location?.longitude))
117+
}
38118
}
39119
}

‎app/src/main/java/com/accenture/beecycle/ui/main/MainIntent.kt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ import com.accenture.beecycle.common.ViewIntent
44

55
sealed class MainIntent : ViewIntent {
66
data class GetCurrentWeather(val latitude: Double?, val longitude: Double?) : MainIntent()
7+
object GetUserBicycles : MainIntent()
8+
object GetUserTeams : MainIntent()
79
}

0 commit comments

Comments
 (0)