Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
TeamPrinterV2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Aleksandr
TeamPrinterV2
Commits
716c048f
Commit
716c048f
authored
Jul 16, 2024
by
Aleksandr
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Details screen (template)
parent
564e344c
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
485 additions
and
184 deletions
+485
-184
app/src/main/java/com/isidroid/c23/Errors.kt
+3
-2
app/src/main/java/com/isidroid/c23/constant/Argument.kt
+5
-0
app/src/main/java/com/isidroid/c23/data/mapper/PrintJobListItemMapper.kt
+30
-0
app/src/main/java/com/isidroid/c23/domain/use_case/DetailsUseCase.kt
+56
-0
app/src/main/java/com/isidroid/c23/domain/use_case/PrintJobsUseCase.kt
+4
-28
app/src/main/java/com/isidroid/c23/ui/navigation/destinations/JobDetailsDestination.kt
+21
-3
app/src/main/java/com/isidroid/c23/ui/screen/details/JobDetailsContract.kt
+13
-2
app/src/main/java/com/isidroid/c23/ui/screen/details/JobDetailsScreen.kt
+166
-10
app/src/main/java/com/isidroid/c23/ui/screen/details/JobDetailsViewModel.kt
+72
-4
app/src/main/java/com/isidroid/c23/ui/screen/details/component/PrintCodeComponent.kt
+49
-0
app/src/main/java/com/isidroid/c23/ui/screen/map/MapScreen.kt
+2
-1
app/src/main/java/com/isidroid/c23/ui/screen/map/_components/TPMapComponent.kt
+2
-5
app/src/main/java/com/isidroid/c23/ui/screen/render_preview/_component/PrintSizeModalComponent.kt
+1
-1
app/src/main/res/values/strings.xml
+3
-0
buildSrc/src/main/java/Versions.kt
+5
-5
ui/maps/build.gradle.kts
+1
-1
ui/maps/src/google/java/com/isidroid/ui/maps/MapsComponent.kt
+26
-4
ui/maps/src/google/java/com/isidroid/ui/maps/_MapComponent.kt
+0
-113
ui/maps/src/google/java/com/isidroid/ui/maps/data/mapper/MapMarkerMapper.kt
+2
-2
ui/maps/src/google/java/com/isidroid/ui/maps/model/MyClusterItem.kt
+3
-1
ui/maps/src/main/java/com/isidroid/ui/maps/ext/ExtGeo.kt
+11
-0
ui/maps/src/main/java/com/isidroid/ui/maps/model/MapMarker.kt
+10
-2
No files found.
app/src/main/java/com/isidroid/c23/Errors.kt
View file @
716c048f
...
@@ -2,4 +2,5 @@ package com.isidroid.c23
...
@@ -2,4 +2,5 @@ package com.isidroid.c23
import
kotlin.jvm.Throws
import
kotlin.jvm.Throws
class
SpotHasNoPrintProfilesException
(
m
:
String
?
=
null
):
Throwable
(
m
)
class
SpotHasNoPrintProfilesException
(
m
:
String
?
=
null
):
Throwable
(
m
)
\ No newline at end of file
class
JobNotFoundException
(
m
:
String
?
=
null
):
Throwable
(
m
)
\ No newline at end of file
app/src/main/java/com/isidroid/c23/constant/Argument.kt
View file @
716c048f
package
com.isidroid.c23.constant
package
com.isidroid.c23.constant
import
androidx.annotation.StringDef
@Retention
(
AnnotationRetention
.
SOURCE
)
@Retention
(
AnnotationRetention
.
SOURCE
)
@StringDef
(
Argument
.
URI
,
Argument
.
LATITUDE
,
Argument
.
LONGITUDE
,
Argument
.
SPOT_CODE
,
Argument
.
ID
,
Argument
.
INFO
,
Argument
.
MARKER
)
annotation
class
Argument
{
annotation
class
Argument
{
companion
object
{
companion
object
{
const
val
URI
=
"URI"
const
val
URI
=
"URI"
...
@@ -8,5 +11,7 @@ annotation class Argument {
...
@@ -8,5 +11,7 @@ annotation class Argument {
const
val
LONGITUDE
=
"LONGITUDE"
const
val
LONGITUDE
=
"LONGITUDE"
const
val
SPOT_CODE
=
"SPOT_CODE"
const
val
SPOT_CODE
=
"SPOT_CODE"
const
val
ID
=
"ID"
const
val
ID
=
"ID"
const
val
INFO
=
"INFO"
const
val
MARKER
=
"MARKER"
}
}
}
}
app/src/main/java/com/isidroid/c23/data/mapper/PrintJobListItemMapper.kt
0 → 100644
View file @
716c048f
package
com.isidroid.c23.data.mapper
import
android.content.Context
import
com.isidroid.c23.domain.dto.PrintJobListItem
import
com.isidroid.c23.ext.getPrintJobStatus
import
com.isidroid.c23.ext.getPrintJobStatusColor
import
com.isidroid.job.model.PrintJob
import
com.isidroid.rendering.constant.printSizeName
import
com.isidroid.spot.model.RichSpot
import
java.io.File
fun
PrintJob
.
createListItem
(
context
:
Context
,
richSpot
:
RichSpot
?):
PrintJobListItem
{
val
profile
=
richSpot
?.
printProfiles
?.
find
{
it
.
id
==
profileId
}
return
PrintJobListItem
(
id
=
id
,
spotCode
=
richSpot
?.
spot
?.
code
,
spotName
=
richSpot
?.
spot
?.
name
?:
"Deleted spot"
,
cost
=
cost
,
paperInfo
=
printSize
.
printSizeName
,
isColor
=
profile
?.
grayscale
!=
true
,
statusColor
=
getPrintJobStatusColor
(
status
),
comment
=
comment
,
copies
=
copies
,
cover
=
sourceFiles
?.
firstOrNull
()
?.
takeIf
{
File
(
it
).
exists
()
},
statusName
=
context
.
getString
(
getPrintJobStatus
(
status
)),
accessCode
=
accessCode
.
orEmpty
(),
createdAt
=
createdAt
,
)
}
\ No newline at end of file
app/src/main/java/com/isidroid/c23/domain/use_case/DetailsUseCase.kt
0 → 100644
View file @
716c048f
package
com.isidroid.c23.domain.use_case
import
android.content.Context
import
com.isidroid.c23.JobNotFoundException
import
com.isidroid.c23.constant.Argument
import
com.isidroid.c23.data.mapper.createListItem
import
com.isidroid.c23.ext.isDebug
import
com.isidroid.core.FlowResult
import
com.isidroid.job.repository.JobRepository
import
com.isidroid.location.repository.LocationRepository
import
com.isidroid.spot.repository.SpotRepository
import
com.isidroid.ui.maps.ext.addKilometerToLatLng
import
com.isidroid.ui.maps.model.MapMarker
import
dagger.hilt.android.qualifiers.ApplicationContext
import
kotlinx.coroutines.flow.flow
import
javax.inject.Inject
import
javax.inject.Singleton
@Singleton
class
DetailsUseCase
@Inject
constructor
(
@ApplicationContext
private
val
context
:
Context
,
private
val
jobRepository
:
JobRepository
,
private
val
spotRepository
:
SpotRepository
,
private
val
locationRepository
:
LocationRepository
,
)
{
fun
loadDetails
(
id
:
String
)
=
flow
{
emit
(
FlowResult
.
Loading
)
val
job
=
jobRepository
.
readLocalList
(
ids
=
listOf
(
id
)).
firstOrNull
()
?:
throw
JobNotFoundException
()
val
richSpot
=
spotRepository
.
findLocalRichSpots
(
ids
=
listOf
(
job
.
spotId
))
?.
firstOrNull
()
val
result
=
job
.
createListItem
(
context
=
context
,
richSpot
=
richSpot
)
val
currentLocation
=
locationRepository
.
getCurrentLocation
()
val
location
=
if
(
isDebug
()
&&
richSpot
?.
spot
!=
null
)
addKilometerToLatLng
(
richSpot
.
spot
.
lat
,
richSpot
.
spot
.
lng
,
distance
=
0.2
)
else
currentLocation
val
mapMarker
=
richSpot
?.
spot
?.
let
{
spot
->
MapMarker
(
id
=
spot
.
id
,
lat
=
spot
.
lat
,
lng
=
spot
.
lng
,
name
=
spot
.
name
)
}
emit
(
FlowResult
.
Success
(
mapOf
(
Argument
.
INFO
to
result
,
Argument
.
LATITUDE
to
location
.
first
,
Argument
.
LONGITUDE
to
location
.
second
,
Argument
.
MARKER
to
mapMarker
)
)
)
}
}
\ No newline at end of file
app/src/main/java/com/isidroid/c23/domain/use_case/PrintJobsUseCase.kt
View file @
716c048f
package
com.isidroid.c23.domain.use_case
package
com.isidroid.c23.domain.use_case
import
android.content.Context
import
android.content.Context
import
com.isidroid.c23.domain.dto.PrintJobListItem
import
com.isidroid.c23.data.mapper.createListItem
import
com.isidroid.c23.ext.getPrintJobStatus
import
com.isidroid.c23.ext.getPrintJobStatusColor
import
com.isidroid.core.FlowResult
import
com.isidroid.core.FlowResult
import
com.isidroid.job.repository.JobRepository
import
com.isidroid.job.repository.JobRepository
import
com.isidroid.rendering.constant.printSizeName
import
com.isidroid.spot.repository.SpotRepository
import
com.isidroid.spot.repository.SpotRepository
import
dagger.hilt.android.qualifiers.ApplicationContext
import
dagger.hilt.android.qualifiers.ApplicationContext
import
kotlinx.coroutines.flow.flow
import
kotlinx.coroutines.flow.flow
import
java.io.File
import
javax.inject.Inject
import
javax.inject.Inject
import
javax.inject.Singleton
import
javax.inject.Singleton
@Singleton
@Singleton
class
PrintJobsUseCase
@Inject
constructor
(
class
PrintJobsUseCase
@Inject
constructor
(
@ApplicationContext
private
val
context
:
Context
,
@ApplicationContext
private
val
context
:
Context
,
private
val
r
epository
:
JobRepository
,
private
val
jobR
epository
:
JobRepository
,
private
val
spotRepository
:
SpotRepository
private
val
spotRepository
:
SpotRepository
)
{
)
{
fun
load
()
=
flow
{
fun
load
()
=
flow
{
emit
(
FlowResult
.
Loading
)
emit
(
FlowResult
.
Loading
)
val
jobList
=
r
epository
.
readLocalList
()
val
jobList
=
jobR
epository
.
readLocalList
()
val
spots
=
jobList
val
spots
=
jobList
.
map
{
it
.
spotId
}
.
map
{
it
.
spotId
}
.
distinct
()
.
distinct
()
.
let
{
spotRepository
.
findLocalRichSpots
(
it
)
}
.
let
{
spotRepository
.
findLocalRichSpots
(
it
)
}
?.
associateBy
({
it
.
spot
.
id
},
{
it
})
?.
associateBy
({
it
.
spot
.
id
},
{
it
})
val
result
=
jobList
.
map
{
job
->
val
result
=
jobList
.
map
{
job
->
job
.
createListItem
(
context
=
context
,
richSpot
=
spots
?.
get
(
job
.
spotId
))
}
val
richSpot
=
spots
?.
get
(
job
.
spotId
)
val
profile
=
richSpot
?.
printProfiles
?.
find
{
it
.
id
==
job
.
profileId
}
PrintJobListItem
(
id
=
job
.
id
,
spotCode
=
richSpot
?.
spot
?.
code
,
spotName
=
richSpot
?.
spot
?.
name
?:
"Deleted spot"
,
cost
=
job
.
cost
,
paperInfo
=
job
.
printSize
.
printSizeName
,
isColor
=
profile
?.
grayscale
!=
true
,
statusColor
=
getPrintJobStatusColor
(
job
.
status
),
comment
=
job
.
comment
,
copies
=
job
.
copies
,
cover
=
job
.
sourceFiles
?.
firstOrNull
()
?.
takeIf
{
File
(
it
).
exists
()
},
statusName
=
context
.
getString
(
getPrintJobStatus
(
job
.
status
)),
accessCode
=
job
.
accessCode
.
orEmpty
(),
createdAt
=
job
.
createdAt
,
)
}
emit
(
FlowResult
.
Success
(
result
))
emit
(
FlowResult
.
Success
(
result
))
}
}
...
...
app/src/main/java/com/isidroid/c23/ui/navigation/destinations/JobDetailsDestination.kt
View file @
716c048f
package
com.isidroid.c23.ui.navigation.destinations
package
com.isidroid.c23.ui.navigation.destinations
import
android.content.Context
import
android.content.Intent
import
android.widget.Toast
import
androidx.compose.runtime.Composable
import
androidx.compose.runtime.Composable
import
androidx.compose.ui.platform.LocalContext
import
androidx.core.net.toUri
import
androidx.hilt.navigation.compose.hiltViewModel
import
androidx.hilt.navigation.compose.hiltViewModel
import
androidx.navigation.NavHostController
import
androidx.navigation.NavHostController
import
com.isidroid.c23.ui.screen.details.JobDetailsContract
import
com.isidroid.c23.ui.screen.details.JobDetailsContract
import
com.isidroid.c23.ui.screen.details.JobDetailsScreen
import
com.isidroid.c23.ui.screen.details.JobDetailsScreen
import
com.isidroid.c23.ui.screen.details.JobDetailsViewModel
import
com.isidroid.c23.ui.screen.details.JobDetailsViewModel
import
com.isidroid.c23.ui.screen.print_jobs.PrintJobsContract
import
com.isidroid.c23.ui.screen.print_jobs.PrintJobsScreen
import
com.isidroid.c23.ui.screen.print_jobs.PrintJobsViewModel
@Composable
@Composable
fun
JobDetailsDestination
(
navController
:
NavHostController
)
{
fun
JobDetailsDestination
(
navController
:
NavHostController
)
{
val
viewModel
:
JobDetailsViewModel
=
hiltViewModel
()
val
viewModel
:
JobDetailsViewModel
=
hiltViewModel
()
val
context
=
LocalContext
.
current
JobDetailsScreen
(
JobDetailsScreen
(
state
=
viewModel
.
viewState
,
state
=
viewModel
.
viewState
,
effectFlow
=
viewModel
.
effect
,
effectFlow
=
viewModel
.
effect
,
spotResultStateFlow
=
viewModel
.
spotResultStateFlow
,
onEventSent
=
{
event
->
viewModel
.
setEvent
(
event
)
},
onEventSent
=
{
event
->
viewModel
.
setEvent
(
event
)
},
onNavigationRequested
=
{
effect
->
onNavigationRequested
=
{
effect
->
when
(
effect
)
{
when
(
effect
)
{
JobDetailsContract
.
Effect
.
Navigation
.
ToBack
->
navController
.
popBackStack
()
JobDetailsContract
.
Effect
.
Navigation
.
ToBack
->
navController
.
popBackStack
()
is
JobDetailsContract
.
Effect
.
Navigation
.
ToNavigationApp
->
context
.
openGoogleMaps
(
lat
=
effect
.
lat
,
lng
=
effect
.
lng
)
}
}
},
},
)
)
}
private
fun
Context
.
openGoogleMaps
(
lat
:
Double
?,
lng
:
Double
?)
{
if
(
lat
==
null
||
lng
==
null
)
return
val
gmmIntentUri
=
"geo:$lat,$lng"
.
toUri
()
val
mapIntent
=
Intent
(
Intent
.
ACTION_VIEW
,
gmmIntentUri
)
// mapIntent.setPackage("com.google.android.apps.maps")
if
(
mapIntent
.
resolveActivity
(
packageManager
)
!=
null
)
{
startActivity
(
mapIntent
)
}
else
{
Toast
.
makeText
(
this
,
"Navigation app not found"
,
Toast
.
LENGTH_LONG
).
show
()
}
}
}
\ No newline at end of file
app/src/main/java/com/isidroid/c23/ui/screen/details/JobDetailsContract.kt
View file @
716c048f
package
com.isidroid.c23.ui.screen.details
package
com.isidroid.c23.ui.screen.details
import
com.isidroid.c23.
ui.screen.content.ContentContract
import
com.isidroid.c23.
domain.dto.PrintJobListItem
import
com.isidroid.core.vm.ViewEvent
import
com.isidroid.core.vm.ViewEvent
import
com.isidroid.core.vm.ViewSideEffect
import
com.isidroid.core.vm.ViewSideEffect
import
com.isidroid.core.vm.ViewState
import
com.isidroid.core.vm.ViewState
...
@@ -8,13 +8,23 @@ import com.isidroid.core.vm.ViewState
...
@@ -8,13 +8,23 @@ import com.isidroid.core.vm.ViewState
class
JobDetailsContract
{
class
JobDetailsContract
{
sealed
interface
Event
:
ViewEvent
{
sealed
interface
Event
:
ViewEvent
{
data
object
ToBack
:
Event
data
object
ToBack
:
Event
data
object
OpenConfirmationMapRoute
:
Event
data
object
DismissBuildRouteConfirmation
:
Event
data
object
OpenNavigationApp
:
Event
}
}
sealed
interface
Effect
:
ViewSideEffect
{
sealed
interface
Effect
:
ViewSideEffect
{
sealed
interface
Navigation
:
Effect
{
sealed
interface
Navigation
:
Effect
{
data
object
ToBack
:
Navigation
data
object
ToBack
:
Navigation
data class
ToNavigationApp
(
val
lat
:
Double
?,
val
lng
:
Double
?)
:
Navigation
}
}
}
}
data class
State
(
val
i
:
Int
=
0
)
:
ViewState
data class
State
(
val
isLoading
:
Boolean
=
false
,
val
printJob
:
PrintJobListItem
?
=
null
,
val
lat
:
Double
?
=
null
,
val
lng
:
Double
?
=
null
,
val
routeConfirmationVisible
:
Boolean
=
false
)
:
ViewState
}
}
\ No newline at end of file
app/src/main/java/com/isidroid/c23/ui/screen/details/JobDetailsScreen.kt
View file @
716c048f
...
@@ -2,37 +2,73 @@ package com.isidroid.c23.ui.screen.details
...
@@ -2,37 +2,73 @@ package com.isidroid.c23.ui.screen.details
import
androidx.activity.compose.BackHandler
import
androidx.activity.compose.BackHandler
import
androidx.compose.foundation.background
import
androidx.compose.foundation.background
import
androidx.compose.foundation.clickable
import
androidx.compose.foundation.layout.Box
import
androidx.compose.foundation.layout.Box
import
androidx.compose.foundation.layout.Column
import
androidx.compose.foundation.layout.WindowInsets
import
androidx.compose.foundation.layout.consumeWindowInsets
import
androidx.compose.foundation.layout.consumeWindowInsets
import
androidx.compose.foundation.layout.displayCutout
import
androidx.compose.foundation.layout.fillMaxSize
import
androidx.compose.foundation.layout.fillMaxSize
import
androidx.compose.foundation.layout.fillMaxWidth
import
androidx.compose.foundation.layout.ime
import
androidx.compose.foundation.layout.navigationBars
import
androidx.compose.foundation.layout.padding
import
androidx.compose.foundation.layout.padding
import
androidx.compose.foundation.layout.statusBars
import
androidx.compose.foundation.shape.RoundedCornerShape
import
androidx.compose.material.Button
import
androidx.compose.material.Icon
import
androidx.compose.material.icons.Icons
import
androidx.compose.material.icons.rounded.Close
import
androidx.compose.material3.BottomSheetDefaults
import
androidx.compose.material3.Card
import
androidx.compose.material3.CardDefaults
import
androidx.compose.material3.ExperimentalMaterial3Api
import
androidx.compose.material3.ExperimentalMaterial3Api
import
androidx.compose.material3.MaterialTheme
import
androidx.compose.material3.ModalBottomSheet
import
androidx.compose.material3.Scaffold
import
androidx.compose.material3.Scaffold
import
androidx.compose.material3.Surface
import
androidx.compose.material3.Surface
import
androidx.compose.material3.Text
import
androidx.compose.material3.Text
import
androidx.compose.material3.TextButton
import
androidx.compose.material3.TopAppBar
import
androidx.compose.material3.TopAppBarDefaults
import
androidx.compose.material3.TopAppBarDefaults
import
androidx.compose.material3.rememberModalBottomSheetState
import
androidx.compose.runtime.Composable
import
androidx.compose.runtime.Composable
import
androidx.compose.runtime.LaunchedEffect
import
androidx.compose.runtime.LaunchedEffect
import
androidx.compose.runtime.State
import
androidx.compose.runtime.State
import
androidx.compose.runtime.mutableStateOf
import
androidx.compose.runtime.getValue
import
androidx.compose.runtime.remember
import
androidx.compose.ui.Alignment
import
androidx.compose.ui.Alignment
import
androidx.compose.ui.Modifier
import
androidx.compose.ui.Modifier
import
androidx.compose.ui.draw.clip
import
androidx.compose.ui.graphics.Color
import
androidx.compose.ui.graphics.Color
import
androidx.compose.ui.res.stringResource
import
androidx.compose.ui.res.stringResource
import
androidx.compose.ui.tooling.preview.Devices
import
androidx.compose.ui.text.font.FontWeight
import
androidx.compose.ui.tooling.preview.Preview
import
androidx.compose.ui.text.style.TextAlign
import
androidx.compose.ui.unit.dp
import
androidx.compose.ui.unit.sp
import
androidx.constraintlayout.compose.ConstraintLayout
import
androidx.constraintlayout.compose.Dimension
import
com.airbnb.lottie.compose.LottieAnimation
import
com.airbnb.lottie.compose.LottieCompositionSpec
import
com.airbnb.lottie.compose.LottieConstants
import
com.airbnb.lottie.compose.rememberLottieComposition
import
com.isidroid.c23.R
import
com.isidroid.c23.R
import
com.isidroid.c23.ui._component.TopAppBarComponent
import
com.isidroid.c23.ui._component.TopAppBarComponent
import
com.isidroid.c23.ui.screen.details.component.PrintCodeComponent
import
com.isidroid.c23.ui.screen.map.MapContract
import
com.isidroid.c23.ui.screen.map._components.TPMapComponent
import
com.isidroid.c23.ui.theme.AppTheme
import
com.isidroid.core.vm.SIDE_EFFECTS_KEY
import
com.isidroid.core.vm.SIDE_EFFECTS_KEY
import
com.isidroid.ui.maps.model.MapMarker
import
kotlinx.coroutines.flow.Flow
import
kotlinx.coroutines.flow.Flow
import
kotlinx.coroutines.flow.collect
import
kotlinx.coroutines.flow.StateFlow
import
timber.log.Timber
@OptIn
(
ExperimentalMaterial3Api
::
class
)
@OptIn
(
ExperimentalMaterial3Api
::
class
)
@Composable
@Composable
fun
JobDetailsScreen
(
fun
JobDetailsScreen
(
state
:
State
<
JobDetailsContract
.
State
>,
state
:
State
<
JobDetailsContract
.
State
>,
effectFlow
:
Flow
<
JobDetailsContract
.
Effect
>?,
effectFlow
:
Flow
<
JobDetailsContract
.
Effect
>?,
spotResultStateFlow
:
StateFlow
<
List
<
MapMarker
>>,
onEventSent
:
(
event
:
JobDetailsContract
.
Event
)
->
Unit
,
onEventSent
:
(
event
:
JobDetailsContract
.
Event
)
->
Unit
,
onNavigationRequested
:
(
navigationEffect
:
JobDetailsContract
.
Effect
.
Navigation
)
->
Unit
,
onNavigationRequested
:
(
navigationEffect
:
JobDetailsContract
.
Effect
.
Navigation
)
->
Unit
,
modifier
:
Modifier
=
Modifier
,
modifier
:
Modifier
=
Modifier
,
...
@@ -47,12 +83,11 @@ fun JobDetailsScreen(
...
@@ -47,12 +83,11 @@ fun JobDetailsScreen(
BackHandler
{
onEventSent
(
JobDetailsContract
.
Event
.
ToBack
)
}
BackHandler
{
onEventSent
(
JobDetailsContract
.
Event
.
ToBack
)
}
Scaffold
(
Scaffold
(
modifier
=
modifier
.
fillMaxSize
(),
modifier
=
modifier
.
fillMaxSize
(),
topBar
=
{
topBar
=
{
TopAppBarComponent
(
TopAppBarComponent
(
text
=
"Print job details"
,
text
=
stringResource
(
id
=
R
.
string
.
print_job_details
)
,
colors
=
TopAppBarDefaults
.
topAppBarColors
(),
colors
=
TopAppBarDefaults
.
topAppBarColors
(),
onNavigationClick
=
{
onEventSent
(
JobDetailsContract
.
Event
.
ToBack
)
}
onNavigationClick
=
{
onEventSent
(
JobDetailsContract
.
Event
.
ToBack
)
}
)
)
...
@@ -60,11 +95,131 @@ fun JobDetailsScreen(
...
@@ -60,11 +95,131 @@ fun JobDetailsScreen(
)
{
paddingValues
->
)
{
paddingValues
->
Box
(
Box
(
modifier
=
Modifier
modifier
=
Modifier
.
padding
(
paddingValues
)
.
consumeWindowInsets
(
paddingValues
)
.
padding
(
top
=
paddingValues
.
calculateTopPadding
())
.
fillMaxSize
(),
.
fillMaxSize
(),
contentAlignment
=
Alignment
.
Center
contentAlignment
=
Alignment
.
TopStart
)
{
)
{
Text
(
"Screen is under construction"
)
when
{
state
.
value
.
isLoading
->
LoadingComponent
()
}
InformationContent
(
state
,
spotResultStateFlow
,
onEventSent
)
DisplayMapRouteConfirmation
(
state
,
onEventSent
)
}
}
}
}
}
}
@Composable
private
fun
LoadingComponent
(
modifier
:
Modifier
=
Modifier
)
{
val
composition
by
rememberLottieComposition
(
LottieCompositionSpec
.
RawRes
(
R
.
raw
.
startapp
))
LottieAnimation
(
composition
=
composition
,
iterations
=
LottieConstants
.
IterateForever
,
modifier
=
modifier
.
fillMaxSize
()
.
padding
(
48
.
dp
)
)
}
@Composable
private
fun
InformationContent
(
state
:
State
<
JobDetailsContract
.
State
>,
spotResultStateFlow
:
StateFlow
<
List
<
MapMarker
>>,
onEventSent
:
(
event
:
JobDetailsContract
.
Event
)
->
Unit
,
modifier
:
Modifier
=
Modifier
)
{
val
information
=
state
.
value
.
printJob
?:
return
ConstraintLayout
(
modifier
=
modifier
.
fillMaxSize
())
{
val
(
codeView
,
statusView
,
mapView
)
=
createRefs
()
PrintCodeComponent
(
code
=
information
.
accessCode
,
modifier
=
Modifier
.
constrainAs
(
codeView
)
{
top
.
linkTo
(
parent
.
top
)
linkTo
(
start
=
parent
.
start
,
end
=
parent
.
end
)
}
)
Text
(
text
=
information
.
statusName
,
fontSize
=
14
.
sp
,
fontWeight
=
FontWeight
.
W200
,
letterSpacing
=
.
76
.
sp
,
color
=
Color
.
White
,
modifier
=
Modifier
.
clip
(
RoundedCornerShape
(
6
.
dp
))
.
background
(
information
.
statusColor
)
.
padding
(
horizontal
=
6
.
dp
,
vertical
=
2
.
dp
)
.
constrainAs
(
statusView
)
{
top
.
linkTo
(
codeView
.
bottom
,
12
.
dp
)
end
.
linkTo
(
parent
.
end
,
12
.
dp
)
}
)
Card
(
modifier
=
Modifier
.
fillMaxWidth
()
.
padding
(
top
=
12
.
dp
)
.
constrainAs
(
mapView
)
{
linkTo
(
top
=
statusView
.
bottom
,
bottom
=
parent
.
bottom
)
height
=
Dimension
.
fillToConstraints
},
shape
=
RoundedCornerShape
(
topStart
=
16
.
dp
,
topEnd
=
16
.
dp
,
bottomStart
=
0
.
dp
,
bottomEnd
=
0
.
dp
),
elevation
=
CardDefaults
.
cardElevation
(
defaultElevation
=
12
.
dp
)
)
{
TPMapComponent
(
modifier
=
Modifier
,
onEventSent
=
{
event
->
when
(
event
)
{
is
MapContract
.
Event
.
ClickOnMarker
->
onEventSent
(
JobDetailsContract
.
Event
.
OpenConfirmationMapRoute
)
else
->
{}
}
},
mapMarkersStateFlow
=
spotResultStateFlow
,
lat
=
state
.
value
.
lat
,
lng
=
state
.
value
.
lng
)
}
}
}
@OptIn
(
ExperimentalMaterial3Api
::
class
)
@Composable
private
fun
DisplayMapRouteConfirmation
(
state
:
State
<
JobDetailsContract
.
State
>,
onEventSent
:
(
event
:
JobDetailsContract
.
Event
)
->
Unit
)
{
if
(!
state
.
value
.
routeConfirmationVisible
)
return
val
sheetState
=
rememberModalBottomSheetState
()
ModalBottomSheet
(
onDismissRequest
=
{
onEventSent
(
JobDetailsContract
.
Event
.
DismissBuildRouteConfirmation
)
},
sheetState
=
sheetState
,
windowInsets
=
WindowInsets
.
statusBars
,
modifier
=
Modifier
.
fillMaxWidth
()
.
padding
(
bottom
=
120
.
dp
),
)
{
Text
(
text
=
stringResource
(
id
=
R
.
string
.
app_navigation_explanation
),
modifier
=
Modifier
.
padding
(
horizontal
=
16
.
dp
),
textAlign
=
TextAlign
.
Center
)
TextButton
(
onClick
=
{
onEventSent
(
JobDetailsContract
.
Event
.
OpenNavigationApp
)
},
modifier
=
Modifier
.
fillMaxWidth
()
.
padding
(
horizontal
=
12
.
dp
,
vertical
=
18
.
dp
)
)
{
Text
(
text
=
"Open in Google Maps"
,
)
}
}
}
\ No newline at end of file
app/src/main/java/com/isidroid/c23/ui/screen/details/JobDetailsViewModel.kt
View file @
716c048f
package
com.isidroid.c23.ui.screen.details
package
com.isidroid.c23.ui.screen.details
import
androidx.compose.material.icons.Icons
import
androidx.compose.material.icons.outlined.AccountCircle
import
androidx.lifecycle.SavedStateHandle
import
androidx.lifecycle.viewModelScope
import
com.isidroid.c23.constant.Argument
import
com.isidroid.c23.domain.dto.PrintJobListItem
import
com.isidroid.c23.domain.use_case.DetailsUseCase
import
com.isidroid.c23.ext.isDebug
import
com.isidroid.c23.ext.isDebug
import
com.isidroid.core.FlowResult
import
com.isidroid.core.vm.BaseViewModel
import
com.isidroid.core.vm.BaseViewModel
import
com.isidroid.ui.maps.model.MapMarker
import
com.isidroid.utils.catchTimber
import
dagger.hilt.android.lifecycle.HiltViewModel
import
dagger.hilt.android.lifecycle.HiltViewModel
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.flow.MutableStateFlow
import
kotlinx.coroutines.flow.asStateFlow
import
kotlinx.coroutines.flow.filterNotNull
import
kotlinx.coroutines.flow.firstOrNull
import
kotlinx.coroutines.flow.flowOn
import
kotlinx.coroutines.flow.onEach
import
kotlinx.coroutines.launch
import
javax.inject.Inject
import
javax.inject.Inject
@HiltViewModel
@HiltViewModel
class
JobDetailsViewModel
@Inject
constructor
()
:
BaseViewModel
<
JobDetailsContract
.
Event
,
JobDetailsContract
.
State
,
JobDetailsContract
.
Effect
>()
{
class
JobDetailsViewModel
@Inject
constructor
(
private
val
useCase
:
DetailsUseCase
,
savedStateHandle
:
SavedStateHandle
)
:
BaseViewModel
<
JobDetailsContract
.
Event
,
JobDetailsContract
.
State
,
JobDetailsContract
.
Effect
>()
{
private
val
_spotResultStateFlow
=
MutableStateFlow
<
List
<
MapMarker
>>(
emptyList
())
val
spotResultStateFlow
=
_spotResultStateFlow
.
asStateFlow
()
init
{
viewModelScope
.
launch
{
savedStateHandle
.
getStateFlow
<
String
?>(
Argument
.
ID
,
null
)
.
filterNotNull
()
.
onEach
{
loadDetails
(
it
)
}
.
firstOrNull
()
}
}
override
val
isDebug
:
Boolean
=
isDebug
()
override
val
isDebug
:
Boolean
=
isDebug
()
override
fun
setInitialState
():
JobDetailsContract
.
State
=
JobDetailsContract
.
State
()
override
fun
setInitialState
():
JobDetailsContract
.
State
=
JobDetailsContract
.
State
()
override
suspend
fun
handleEvents
(
event
:
JobDetailsContract
.
Event
)
{
override
suspend
fun
handleEvents
(
event
:
JobDetailsContract
.
Event
)
{
when
(
event
){
when
(
event
)
{
JobDetailsContract
.
Event
.
ToBack
->
setEffect
{
JobDetailsContract
.
Effect
.
Navigation
.
ToBack
}
JobDetailsContract
.
Event
.
ToBack
->
setEffect
{
JobDetailsContract
.
Effect
.
Navigation
.
ToBack
}
}
JobDetailsContract
.
Event
.
OpenConfirmationMapRoute
->
setState
{
copy
(
routeConfirmationVisible
=
true
)
}
JobDetailsContract
.
Event
.
DismissBuildRouteConfirmation
->
setState
{
copy
(
routeConfirmationVisible
=
false
)
}
JobDetailsContract
.
Event
.
OpenNavigationApp
->
openNavigationApp
()
}
}
// handle events
private
suspend
fun
loadDetails
(
id
:
String
)
{
useCase
.
loadDetails
(
id
)
.
flowOn
(
Dispatchers
.
IO
)
.
catchTimber
{
}
.
collect
{
res
->
when
(
res
)
{
FlowResult
.
Loading
->
setState
{
copy
(
isLoading
=
true
)
}
is
FlowResult
.
Success
->
onDetails
(
item
=
res
.
result
[
Argument
.
INFO
]
as
?
PrintJobListItem
,
lat
=
res
.
result
[
Argument
.
LATITUDE
]
as
?
Double
,
lng
=
res
.
result
[
Argument
.
LONGITUDE
]
as
?
Double
,
mapMarker
=
res
.
result
[
Argument
.
MARKER
]
as
?
MapMarker
)
}
}
}
private
suspend
fun
onDetails
(
item
:
PrintJobListItem
?,
lat
:
Double
?,
lng
:
Double
?,
mapMarker
:
MapMarker
?)
{
val
myLocation
=
MapMarker
(
id
=
"my_location"
,
lat
=
lat
?:
0.0
,
lng
=
lng
?:
0.0
,
name
=
"My location"
,
imageVector
=
Icons
.
Outlined
.
AccountCircle
)
_spotResultStateFlow
.
emit
(
listOfNotNull
(
mapMarker
,
myLocation
))
setState
{
copy
(
isLoading
=
false
,
printJob
=
item
,
lat
=
lat
,
lng
=
lng
)
}
}
private
fun
openNavigationApp
(){
setState
{
copy
(
routeConfirmationVisible
=
false
)
}
setEffect
{
JobDetailsContract
.
Effect
.
Navigation
.
ToNavigationApp
(
viewState
.
value
.
lat
,
viewState
.
value
.
lng
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/com/isidroid/c23/ui/screen/details/component/PrintCodeComponent.kt
0 → 100644
View file @
716c048f
package
com.isidroid.c23.ui.screen.details.component
import
androidx.compose.foundation.background
import
androidx.compose.foundation.layout.Row
import
androidx.compose.foundation.layout.padding
import
androidx.compose.foundation.shape.RoundedCornerShape
import
androidx.compose.material3.MaterialTheme
import
androidx.compose.material3.Surface
import
androidx.compose.material3.Text
import
androidx.compose.runtime.Composable
import
androidx.compose.ui.Modifier
import
androidx.compose.ui.graphics.Color
import
androidx.compose.ui.tooling.preview.Preview
import
androidx.compose.ui.unit.dp
import
androidx.compose.ui.unit.sp
@Composable
fun
PrintCodeComponent
(
code
:
String
,
modifier
:
Modifier
=
Modifier
)
{
Row
(
modifier
=
modifier
)
{
for
(
c
in
code
)
PrintCodeElement
(
c
)
}
}
@Composable
private
fun
PrintCodeElement
(
c
:
Char
)
{
Text
(
text
=
"$c"
,
fontSize
=
24
.
sp
,
color
=
Color
.
White
,
style
=
MaterialTheme
.
typography
.
displayLarge
,
modifier
=
Modifier
.
padding
(
horizontal
=
8
.
dp
,
vertical
=
8
.
dp
)
.
background
(
Color
.
Blue
,
RoundedCornerShape
(
6
.
dp
))
.
padding
(
horizontal
=
12
.
dp
,
vertical
=
0
.
dp
)
)
}
@Preview
@Composable
fun
PrintCodeComponentPreview
()
{
Surface
{
PrintCodeComponent
(
"7819128"
)
}
}
\ No newline at end of file
app/src/main/java/com/isidroid/c23/ui/screen/map/MapScreen.kt
View file @
716c048f
...
@@ -68,7 +68,8 @@ fun MapScreen(
...
@@ -68,7 +68,8 @@ fun MapScreen(
}
}
)
{
paddingValues
->
)
{
paddingValues
->
TPMapComponent
(
TPMapComponent
(
state
=
state
,
lat
=
state
.
value
.
lat
,
lng
=
state
.
value
.
lng
,
modifier
=
Modifier
modifier
=
Modifier
.
fillMaxSize
()
.
fillMaxSize
()
.
consumeWindowInsets
(
paddingValues
),
.
consumeWindowInsets
(
paddingValues
),
...
...
app/src/main/java/com/isidroid/c23/ui/screen/map/_components/TPMapComponent.kt
View file @
716c048f
package
com.isidroid.c23.ui.screen.map._components
package
com.isidroid.c23.ui.screen.map._components
import
androidx.compose.runtime.Composable
import
androidx.compose.runtime.Composable
import
androidx.compose.runtime.State
import
androidx.compose.ui.Modifier
import
androidx.compose.ui.Modifier
import
com.isidroid.c23.ui.screen.map.MapContract
import
com.isidroid.c23.ui.screen.map.MapContract
import
com.isidroid.ui.maps.model.MapMarker
import
com.isidroid.ui.maps.model.MapMarker
...
@@ -11,13 +10,11 @@ import kotlinx.coroutines.flow.StateFlow
...
@@ -11,13 +10,11 @@ import kotlinx.coroutines.flow.StateFlow
@Composable
@Composable
fun
TPMapComponent
(
fun
TPMapComponent
(
onEventSent
:
(
event
:
MapContract
.
Event
)
->
Unit
,
onEventSent
:
(
event
:
MapContract
.
Event
)
->
Unit
,
state
:
State
<
MapContract
.
State
>,
lat
:
Double
?,
lng
:
Double
?,
mapMarkersStateFlow
:
StateFlow
<
List
<
MapMarker
>>,
mapMarkersStateFlow
:
StateFlow
<
List
<
MapMarker
>>,
modifier
:
Modifier
=
Modifier
modifier
:
Modifier
=
Modifier
)
{
)
{
val
lat
=
state
.
value
.
lat
val
lng
=
state
.
value
.
lng
if
(
lat
==
null
||
lng
==
null
)
if
(
lat
==
null
||
lng
==
null
)
return
return
...
...
app/src/main/java/com/isidroid/c23/ui/screen/render_preview/_component/PrintSizeModalComponent.kt
View file @
716c048f
...
@@ -148,7 +148,7 @@ private fun OptionsModalComponent(
...
@@ -148,7 +148,7 @@ private fun OptionsModalComponent(
sheetState
=
sheetState
,
sheetState
=
sheetState
,
modifier
=
modifier
.
fillMaxWidth
(),
modifier
=
modifier
.
fillMaxWidth
(),
)
{
)
{
Column
(
modifier
=
m
odifier
.
fillMaxWidth
())
{
Column
(
modifier
=
M
odifier
.
fillMaxWidth
())
{
TopAppBar
(
TopAppBar
(
title
=
{
Text
(
text
=
stringResource
(
id
=
title
))
},
title
=
{
Text
(
text
=
stringResource
(
id
=
title
))
},
navigationIcon
=
{
Icon
(
Icons
.
Rounded
.
Close
,
contentDescription
=
null
,
modifier
=
Modifier
.
clickable
{
onCancel
()
})
},
navigationIcon
=
{
Icon
(
Icons
.
Rounded
.
Close
,
contentDescription
=
null
,
modifier
=
Modifier
.
clickable
{
onCancel
()
})
},
...
...
app/src/main/res/values/strings.xml
View file @
716c048f
...
@@ -38,4 +38,6 @@
...
@@ -38,4 +38,6 @@
<string
name=
"print_job_list"
>
My Print jobs
</string>
<string
name=
"print_job_list"
>
My Print jobs
</string>
<string
name=
"rendered_files_copied_message"
>
Successfully copied %d files
</string>
<string
name=
"rendered_files_copied_message"
>
Successfully copied %d files
</string>
<string
name=
"empty"
/>
<string
name=
"empty"
/>
<string
name=
"print_job_details"
>
Job details
</string>
<string
name=
"app_navigation_explanation"
>
To navigate to this location, please use an external navigation app. Tap the button below to open your preferred navigation app and plan your route.
</string>
</resources>
</resources>
\ No newline at end of file
buildSrc/src/main/java/Versions.kt
View file @
716c048f
...
@@ -4,7 +4,7 @@ object BuildVersions {
...
@@ -4,7 +4,7 @@ object BuildVersions {
const
val
TARGET_SDK
=
34
const
val
TARGET_SDK
=
34
const
val
KOTLIN_COMPILER_EXT_VERSION
=
"1.5.3"
const
val
KOTLIN_COMPILER_EXT_VERSION
=
"1.5.3"
const
val
ANDROID_PLUGIN
=
"8.5.
0
"
const
val
ANDROID_PLUGIN
=
"8.5.
1
"
const
val
KOTLIN
=
"1.9.10"
const
val
KOTLIN
=
"1.9.10"
const
val
KSP
=
"1.9.10-1.0.13"
const
val
KSP
=
"1.9.10-1.0.13"
}
}
...
@@ -21,7 +21,7 @@ object GoogleVersions {
...
@@ -21,7 +21,7 @@ object GoogleVersions {
const
val
hilt
=
"2.49"
const
val
hilt
=
"2.49"
const
val
hiltNavigationCompose
=
"1.2.0"
const
val
hiltNavigationCompose
=
"1.2.0"
const
val
hiltWork
=
"1.0.0"
const
val
hiltWork
=
"1.0.0"
const
val
lifecycle
=
"2.8.
2
"
const
val
lifecycle
=
"2.8.
3
"
const
val
navigation
=
"2.7.0"
const
val
navigation
=
"2.7.0"
const
val
navigationCompose
=
"2.7.7"
const
val
navigationCompose
=
"2.7.7"
const
val
preferences
=
"1.2.1"
const
val
preferences
=
"1.2.1"
...
@@ -29,7 +29,7 @@ object GoogleVersions {
...
@@ -29,7 +29,7 @@ object GoogleVersions {
const
val
roomCompiler
=
"2.5.1"
const
val
roomCompiler
=
"2.5.1"
const
val
splash
=
"1.0.1"
const
val
splash
=
"1.0.1"
const
val
work
=
"2.9.0"
const
val
work
=
"2.9.0"
const
val
services
=
"4.4.
1
"
const
val
services
=
"4.4.
2
"
const
val
constraint
=
"1.0.1"
const
val
constraint
=
"1.0.1"
const
val
paging
=
"3.2.1"
const
val
paging
=
"3.2.1"
const
val
materialView
=
"1.11.0"
const
val
materialView
=
"1.11.0"
...
@@ -51,14 +51,14 @@ object NetworkVersions {
...
@@ -51,14 +51,14 @@ object NetworkVersions {
object
FirebaseDependencies
{
object
FirebaseDependencies
{
const
val
analytics
=
"com.google.firebase:firebase-analytics-ktx"
const
val
analytics
=
"com.google.firebase:firebase-analytics-ktx"
const
val
bom
=
"33.1.
1
"
const
val
bom
=
"33.1.
2
"
const
val
crashlytics
=
"com.google.firebase:firebase-crashlytics-ktx"
const
val
crashlytics
=
"com.google.firebase:firebase-crashlytics-ktx"
const
val
messaging
=
"com.google.firebase:firebase-messaging-ktx"
const
val
messaging
=
"com.google.firebase:firebase-messaging-ktx"
const
val
config
=
"com.google.firebase:firebase-config-ktx"
const
val
config
=
"com.google.firebase:firebase-config-ktx"
}
}
object
FirebaseVersions
{
object
FirebaseVersions
{
const
val
crashlyticsPlugin
=
"
2.9.9
"
const
val
crashlyticsPlugin
=
"
3.0.2
"
}
}
object
ToolsVersions
{
object
ToolsVersions
{
...
...
ui/maps/build.gradle.kts
View file @
716c048f
...
@@ -78,7 +78,7 @@ dependencies {
...
@@ -78,7 +78,7 @@ dependencies {
googleImplementation("com.google.maps.android:maps-compose:${GoogleVersions.maps}")
googleImplementation("com.google.maps.android:maps-compose:${GoogleVersions.maps}")
googleImplementation("com.google.maps.android:android-maps-utils:${GoogleVersions.mapUtils}")
googleImplementation("com.google.maps.android:android-maps-utils:${GoogleVersions.mapUtils}")
googleImplementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.
1
")
googleImplementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.
3
")
googleImplementation("com.google.maps.android:maps-compose-utils:2.11.4")
googleImplementation("com.google.maps.android:maps-compose-utils:2.11.4")
googleImplementation("com.google.maps.android:maps-compose-widgets:2.11.4")
googleImplementation("com.google.maps.android:maps-compose-widgets:2.11.4")
...
...
ui/maps/src/google/java/com/isidroid/ui/maps/MapsComponent.kt
View file @
716c048f
package
com.isidroid.ui.maps
package
com.isidroid.ui.maps
import
androidx.compose.foundation.Image
import
androidx.compose.foundation.background
import
androidx.compose.foundation.background
import
androidx.compose.foundation.layout.Box
import
androidx.compose.foundation.layout.Box
import
androidx.compose.foundation.layout.fillMaxSize
import
androidx.compose.foundation.layout.fillMaxSize
import
androidx.compose.foundation.layout.height
import
androidx.compose.foundation.layout.padding
import
androidx.compose.foundation.layout.padding
import
androidx.compose.foundation.layout.width
import
androidx.compose.foundation.shape.CircleShape
import
androidx.compose.foundation.shape.CircleShape
import
androidx.compose.material.icons.Icons
import
androidx.compose.material.icons.Icons
import
androidx.compose.material.icons.filled.LocationOn
import
androidx.compose.material.icons.filled.LocationOn
import
androidx.compose.material.icons.filled.Place
import
androidx.compose.material.icons.outlined.MailOutline
import
androidx.compose.material.icons.rounded.LocationOn
import
androidx.compose.material3.Icon
import
androidx.compose.material3.Icon
import
androidx.compose.material3.IconButton
import
androidx.compose.material3.IconButton
import
androidx.compose.runtime.Composable
import
androidx.compose.runtime.Composable
...
@@ -16,13 +22,16 @@ import androidx.compose.runtime.remember
...
@@ -16,13 +22,16 @@ import androidx.compose.runtime.remember
import
androidx.compose.runtime.snapshotFlow
import
androidx.compose.runtime.snapshotFlow
import
androidx.compose.ui.Alignment
import
androidx.compose.ui.Alignment
import
androidx.compose.ui.Modifier
import
androidx.compose.ui.Modifier
import
androidx.compose.ui.draw.scale
import
androidx.compose.ui.graphics.Color
import
androidx.compose.ui.graphics.Color
import
androidx.compose.ui.platform.LocalContext
import
androidx.compose.ui.platform.LocalLifecycleOwner
import
androidx.compose.ui.platform.LocalLifecycleOwner
import
androidx.compose.ui.unit.dp
import
androidx.compose.ui.unit.dp
import
androidx.lifecycle.flowWithLifecycle
import
androidx.lifecycle.flowWithLifecycle
import
com.google.android.gms.maps.CameraUpdateFactory
import
com.google.android.gms.maps.CameraUpdateFactory
import
com.google.android.gms.maps.model.CameraPosition
import
com.google.android.gms.maps.model.CameraPosition
import
com.google.android.gms.maps.model.LatLng
import
com.google.android.gms.maps.model.LatLng
import
com.google.maps.android.clustering.ClusterManager
import
com.google.maps.android.compose.GoogleMap
import
com.google.maps.android.compose.GoogleMap
import
com.google.maps.android.compose.MapProperties
import
com.google.maps.android.compose.MapProperties
import
com.google.maps.android.compose.MapUiSettings
import
com.google.maps.android.compose.MapUiSettings
...
@@ -53,6 +62,7 @@ fun MapsComponent(
...
@@ -53,6 +62,7 @@ fun MapsComponent(
val
items
=
mapMarkersStateFlow
.
collectAsState
()
val
items
=
mapMarkersStateFlow
.
collectAsState
()
val
stateFlow
=
remember
{
MutableStateFlow
(
LatLng
(
lat
,
lng
))
}
val
stateFlow
=
remember
{
MutableStateFlow
(
LatLng
(
lat
,
lng
))
}
val
lifecycleOwner
=
LocalLifecycleOwner
.
current
val
lifecycleOwner
=
LocalLifecycleOwner
.
current
val
context
=
LocalContext
.
current
LaunchedEffect
(
cameraPositionState
)
{
LaunchedEffect
(
cameraPositionState
)
{
snapshotFlow
{
cameraPositionState
.
position
}
snapshotFlow
{
cameraPositionState
.
position
}
...
@@ -79,12 +89,13 @@ fun MapsComponent(
...
@@ -79,12 +89,13 @@ fun MapsComponent(
modifier
=
modifier
.
fillMaxSize
(),
modifier
=
modifier
.
fillMaxSize
(),
properties
=
MapProperties
(
isMyLocationEnabled
=
false
),
properties
=
MapProperties
(
isMyLocationEnabled
=
false
),
cameraPositionState
=
cameraPositionState
,
cameraPositionState
=
cameraPositionState
,
uiSettings
=
MapUiSettings
(
zoomControlsEnabled
=
false
),
uiSettings
=
MapUiSettings
(
zoomControlsEnabled
=
true
),
onMapLoaded
=
{},
onMapLoaded
=
{},
onMapClick
=
{},
onMapClick
=
{},
onMyLocationClick
=
{},
onMyLocationClick
=
{},
)
{
)
{
val
parkMarkers
=
items
.
value
.
map
{
it
.
transformToClusterItem
()
}
val
parkMarkers
=
items
.
value
.
map
{
it
.
transformToClusterItem
()
}
Clustering
(
Clustering
(
items
=
parkMarkers
,
items
=
parkMarkers
,
onClusterItemClick
=
{
onClusterItemClick
=
{
...
@@ -96,15 +107,26 @@ fun MapsComponent(
...
@@ -96,15 +107,26 @@ fun MapsComponent(
true
true
},
},
onClusterItemInfoWindowClick
=
{},
onClusterItemInfoWindowClick
=
{},
clusterItemContent
=
{
if
(
it
.
imageVector
!=
null
)
Icon
(
it
.
imageVector
,
contentDescription
=
null
)
else
Icon
(
Icons
.
Default
.
Place
,
contentDescription
=
null
,
tint
=
Color
.
Red
,
modifier
=
Modifier
.
scale
(
1.2f
)
)
}
)
)
}
}
IconButton
(
IconButton
(
onClick
=
{
moveCameraToMyLocation
()
},
onClick
=
{
moveCameraToMyLocation
()
},
modifier
=
Modifier
modifier
=
Modifier
.
align
(
Alignment
.
Bottom
End
)
.
align
(
Alignment
.
Bottom
Start
)
.
padding
(
bottom
=
72
.
dp
,
end
=
12
.
dp
)
.
padding
(
bottom
=
72
.
dp
,
start
=
12
.
dp
)
.
background
(
Color
.
Black
,
CircleShape
)
.
background
(
Color
.
Black
.
copy
(
alpha
=
.
45f
)
,
CircleShape
)
)
{
)
{
Icon
(
Icon
(
imageVector
=
Icons
.
Default
.
LocationOn
,
imageVector
=
Icons
.
Default
.
LocationOn
,
...
...
ui/maps/src/google/java/com/isidroid/ui/maps/_MapComponent.kt
deleted
100644 → 0
View file @
564e344c
package
com.isidroid.ui.maps
// val context = LocalContext.current
// val lifecycleOwner = LocalLifecycleOwner.current
//
// val stateFlow = remember { MutableStateFlow(LatLng(lat, lng)) }
// var googleMapView by remember { mutableStateOf<GoogleMap?>(null) }
// var clusterManager by remember { mutableStateOf<ClusterManager<MyClusterItem>?>(null) }
//
//
// LaunchedEffect(stateFlow) {
// stateFlow
// .flowWithLifecycle(lifecycleOwner.lifecycle)
// .distinctUntilChanged()
// .debounce(1000L)
// .collect { newLatLng ->
// val radius = findMapRadius(googleMapView)
// onCameraMove(newLatLng.latitude, newLatLng.longitude, radius)
// }
// }
//
// MapCreatorComponent(
// modifier = modifier,
// stateFlow = stateFlow,
// onMapViewReady = { map, manager ->
// googleMapView = map
// clusterManager = manager
//
// Timber.i("sdfsdfsdf MapCreatorComponent.onMapViewReady")
//
//// map.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(lat, lng), 16f))
// }
// )
//
// HandleCallbacks(mapMarkersStateFlow, clusterManager)
//
// LaunchedEffect(stateFlow) {
// stateFlow
// .flowWithLifecycle(lifecycleOwner.lifecycle)
// .distinctUntilChanged()
// .debounce(1000L)
// .collect { newLatLng ->
// val radius = findMapRadius(googleMapView)
// onCameraMove(newLatLng.latitude, newLatLng.longitude, radius)
// }
// }
//}
//
//@Composable
//private fun HandleCallbacks(mapMarkersStateFlow: StateFlow<List<MapMarker>>, clusterManager: ClusterManager<MyClusterItem>?) {
//// val coroutineScope = rememberCoroutineScope()
// val mapMarkers = mapMarkersStateFlow.collectAsState()
////
//// Timber.i("sdfsdfsdf mapMarkers=${mapMarkers.value.size}, clusterManager=$clusterManager")
//}
//
//@Composable
//private fun MapCreatorComponent(
// modifier: Modifier,
// stateFlow: MutableStateFlow<LatLng>,
// onMapViewReady: (GoogleMap, ClusterManager<MyClusterItem>) -> Unit
//) {
// val mapView = rememberMapViewWithLifecycle()
// val context = LocalContext.current
// val coroutineScope = rememberCoroutineScope()
// var isCreated by remember { mutableStateOf(false) }
//
// Timber.i("sdfsdfsdf MapCreatorComponent create isCreated=$isCreated")
//
// if(isCreated) return
//
// AndroidView(
// factory = { mapView },
// modifier = modifier
// ) {
// mapView.getMapAsync { googleMap ->
// Timber.i("sdfsdfsdf MapCreatorComponent.onMapViewReady")
// isCreated = true
//
//
// val clusterManager = ClusterManager<MyClusterItem>(context, googleMap)
// onMapViewReady(googleMap, clusterManager)
//
// googleMap.setOnCameraIdleListener(clusterManager)
// googleMap.setOnMarkerClickListener(clusterManager)
//
// clusterManager.setOnClusterClickListener { clusterItem ->
// true
// }
//
// clusterManager.setOnClusterItemClickListener { clusterItem -> true }
// googleMap.setOnCameraMoveListener {
// val centerLocation = googleMap.cameraPosition.target
// coroutineScope.launch { stateFlow.emit(centerLocation) }
// }
// }
// }
//}
//
//
////private fun addClusteredMarkers(clusterManager: ClusterManager<MyClusterItem>) {
//// val items = listOf(
//// MyClusterItem(LatLng(40.7579247, -73.9881229), "Title 1", "Snippet 1"),
//// MyClusterItem(LatLng(40.7579347, -73.9881129), "Title 2", "Snippet 2"),
//// MyClusterItem(LatLng(40.7579347, -73.9851129), "Title 3", "Snippet 2")
////
//// )
////
//// clusterManager.clearItems()
//// clusterManager.addItems(items)
//// clusterManager.cluster()
////}
\ No newline at end of file
ui/maps/src/google/java/com/isidroid/ui/maps/data/mapper/MapMarkerMapper.kt
View file @
716c048f
...
@@ -4,4 +4,4 @@ import com.google.android.gms.maps.model.LatLng
...
@@ -4,4 +4,4 @@ import com.google.android.gms.maps.model.LatLng
import
com.isidroid.ui.maps.model.MapMarker
import
com.isidroid.ui.maps.model.MapMarker
import
com.isidroid.ui.maps.model.MyClusterItem
import
com.isidroid.ui.maps.model.MyClusterItem
fun
MapMarker
.
transformToClusterItem
()
=
MyClusterItem
(
latLng
=
LatLng
(
lat
,
lng
),
title
=
name
,
snippet
=
""
,
id
=
id
)
fun
MapMarker
.
transformToClusterItem
()
=
MyClusterItem
(
latLng
=
LatLng
(
lat
,
lng
),
title
=
name
,
snippet
=
""
,
id
=
id
,
imageVector
=
imageVector
)
\ No newline at end of file
\ No newline at end of file
ui/maps/src/google/java/com/isidroid/ui/maps/model/MyClusterItem.kt
View file @
716c048f
package
com.isidroid.ui.maps.model
package
com.isidroid.ui.maps.model
import
androidx.compose.ui.graphics.vector.ImageVector
import
com.google.android.gms.maps.model.LatLng
import
com.google.android.gms.maps.model.LatLng
import
com.google.maps.android.clustering.ClusterItem
import
com.google.maps.android.clustering.ClusterItem
...
@@ -7,7 +8,8 @@ data class MyClusterItem(
...
@@ -7,7 +8,8 @@ data class MyClusterItem(
val
id
:
String
,
val
id
:
String
,
private
val
latLng
:
LatLng
,
private
val
latLng
:
LatLng
,
private
val
title
:
String
,
private
val
title
:
String
,
private
val
snippet
:
String
private
val
snippet
:
String
,
val
imageVector
:
ImageVector
?
=
null
)
:
ClusterItem
{
)
:
ClusterItem
{
override
fun
getPosition
():
LatLng
=
latLng
override
fun
getPosition
():
LatLng
=
latLng
override
fun
getTitle
():
String
=
title
override
fun
getTitle
():
String
=
title
...
...
ui/maps/src/main/java/com/isidroid/ui/maps/ext/ExtGeo.kt
0 → 100644
View file @
716c048f
package
com.isidroid.ui.maps.ext
// Константы
const
val
EARTH_RADIUS
=
6371.0
// Радиус Земли в километрах
fun
addKilometerToLatLng
(
lat
:
Double
,
lng
:
Double
,
distance
:
Double
=
1.0
):
Pair
<
Double
,
Double
>
{
val
latInRadians
=
Math
.
toRadians
(
lat
)
val
newLat
=
latInRadians
+
distance
/
EARTH_RADIUS
val
newLatInDegrees
=
Math
.
toDegrees
(
newLat
)
return
Pair
(
newLatInDegrees
,
lng
)
}
ui/maps/src/main/java/com/isidroid/ui/maps/model/MapMarker.kt
View file @
716c048f
package
com.isidroid.ui.maps.model
package
com.isidroid.ui.maps.model
data class
MapMarker
(
val
id
:
String
,
val
name
:
String
,
val
lat
:
Double
,
val
lng
:
Double
)
import
androidx.compose.ui.graphics.vector.ImageVector
\ No newline at end of file
data class
MapMarker
(
val
id
:
String
,
val
name
:
String
,
val
lat
:
Double
,
val
lng
:
Double
,
val
imageVector
:
ImageVector
?
=
null
)
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment