From 41f66d650ab86c2d8c70a70362f55d52a9d0bd02 Mon Sep 17 00:00:00 2001 From: AllenTom Date: Mon, 15 Jul 2024 19:02:42 +0800 Subject: [PATCH] update:add new post --- app/build.gradle.kts | 4 + .../java/com/aiosman/riderpro/FollowerPage.kt | 6 +- .../java/com/aiosman/riderpro/MainActivity.kt | 7 +- .../com/aiosman/riderpro/ModificationList.kt | 6 +- .../main/java/com/aiosman/riderpro/NewPost.kt | 110 +++++++++++++++--- .../com/aiosman/riderpro/NewPostViewModel.kt | 11 ++ .../aiosman/riderpro/SelectLocationModal.kt | 101 +++++++++++++--- 7 files changed, 203 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/com/aiosman/riderpro/NewPostViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 48cceed..a657125 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -76,4 +76,8 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) + // coil + implementation("io.coil-kt:coil-compose:2.6.0") + implementation("io.coil-kt:coil:2.6.0") + implementation ("com.google.android.libraries.places:places:3.3.0") } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/FollowerPage.kt b/app/src/main/java/com/aiosman/riderpro/FollowerPage.kt index 4d6dea2..0335b70 100644 --- a/app/src/main/java/com/aiosman/riderpro/FollowerPage.kt +++ b/app/src/main/java/com/aiosman/riderpro/FollowerPage.kt @@ -27,11 +27,11 @@ import androidx.compose.ui.unit.sp @Preview @Composable fun FollowerPage() { + val heightOfStatusBar = 24.dp Column( modifier = Modifier - .fillMaxSize() - .background(color = Color(0xFFFFFFFF)) - .padding(16.dp) + .padding(top = 16.dp + 24.dp, start = 16.dp, end = 16.dp) + ) { NoticeScreenHeader("FOLLOWERS") Spacer(modifier = Modifier.height(28.dp)) diff --git a/app/src/main/java/com/aiosman/riderpro/MainActivity.kt b/app/src/main/java/com/aiosman/riderpro/MainActivity.kt index 5972369..63cb0b5 100644 --- a/app/src/main/java/com/aiosman/riderpro/MainActivity.kt +++ b/app/src/main/java/com/aiosman/riderpro/MainActivity.kt @@ -44,13 +44,16 @@ import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.aiosman.riderpro.ui.theme.RiderProTheme import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.google.android.libraries.places.api.Places class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) - + if (!Places.isInitialized()) { + Places.initialize(applicationContext,"AIzaSyDpgLDH1-SECw_pdjJq_msynq1XrxwgKVI") + } enableEdgeToEdge() setContent { Navigation() @@ -154,7 +157,7 @@ fun NavigationController(navController: NavHostController) { } composable(route = "Followers") { Box( - modifier = Modifier.padding(navigationBarHeight) + modifier = Modifier.padding() ) { FollowerPage() } diff --git a/app/src/main/java/com/aiosman/riderpro/ModificationList.kt b/app/src/main/java/com/aiosman/riderpro/ModificationList.kt index 548bc7d..f13909a 100644 --- a/app/src/main/java/com/aiosman/riderpro/ModificationList.kt +++ b/app/src/main/java/com/aiosman/riderpro/ModificationList.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.R @@ -30,12 +31,15 @@ import com.aiosman.riderpro.R @Preview @Composable fun ModificationListScreen() { + val navController = LocalNavController.current val modifications = getModifications() Column(modifier = Modifier.fillMaxSize().background(Color(0xFFF8F8F8))) { TopAppBar( title = { Text("Modification List") }, navigationIcon = { - IconButton(onClick = { /* Handle back button click */ }) { + IconButton(onClick = { + navController.popBackStack() + }) { Icon( painter = painterResource(id = R.drawable.rider_pro_nav_back), // Replace with your back icon contentDescription = "Back" diff --git a/app/src/main/java/com/aiosman/riderpro/NewPost.kt b/app/src/main/java/com/aiosman/riderpro/NewPost.kt index e4ec94d..176a108 100644 --- a/app/src/main/java/com/aiosman/riderpro/NewPost.kt +++ b/app/src/main/java/com/aiosman/riderpro/NewPost.kt @@ -1,5 +1,9 @@ package com.aiosman.riderpro +import android.app.Activity +import android.content.Intent +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -32,20 +36,26 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage + @Preview @Composable fun NewPostScreen() { + val model = NewPostViewModel Column( modifier = Modifier .fillMaxSize() - ) { NewPostTopBar() - NewPostTextField("What's on your mind?") + NewPostTextField("Share your adventure…", model.textContent) { + model.textContent = it + } AddImageGrid() AdditionalPostItem() } @@ -53,11 +63,11 @@ fun NewPostScreen() { @Composable fun NewPostTopBar() { + val navController = LocalNavController.current Box( modifier = Modifier .fillMaxWidth() .padding(horizontal = 18.dp, vertical = 10.dp) - ) { Row( modifier = Modifier.align(Alignment.CenterStart), @@ -65,7 +75,9 @@ fun NewPostTopBar() { Image( painter = painterResource(id = R.drawable.rider_pro_close), contentDescription = "Back", - modifier = Modifier.size(24.dp) + modifier = Modifier.size(24.dp).clickable { + navController.popBackStack() + } ) Spacer(modifier = Modifier.weight(1f)) Image( @@ -79,20 +91,19 @@ fun NewPostTopBar() { } @Composable -fun NewPostTextField(hint: String) { - var text by remember { mutableStateOf("") } +fun NewPostTextField(hint: String, value: String, onValueChange: (String) -> Unit) { Box(modifier = Modifier.fillMaxWidth()) { BasicTextField( - value = text, - onValueChange = { text = it }, + value = value, + onValueChange = onValueChange, modifier = Modifier .fillMaxWidth() .heightIn(200.dp) .padding(horizontal = 18.dp, vertical = 10.dp) ) - if (text.isEmpty()) { + if (value.isEmpty()) { Text( text = hint, color = Color.Gray, @@ -105,6 +116,18 @@ fun NewPostTextField(hint: String) { @OptIn(ExperimentalLayoutApi::class) @Composable fun AddImageGrid() { + val context = LocalContext.current + var imageUriList by remember { mutableStateOf(listOf()) } + val pickImageLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val uri = result.data?.data + if (uri != null) { + imageUriList = imageUriList + uri.toString() + } + } + } val stroke = Stroke( width = 2f, pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f) @@ -119,9 +142,9 @@ fun AddImageGrid() { verticalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - repeat(5) { - Image( - painter = painterResource(id = R.drawable.rider_pro_moment_demo_1), + imageUriList.forEach { + AsyncImage( + it, contentDescription = "Add Image", modifier = Modifier.size(110.dp), contentScale = ContentScale.Crop @@ -133,6 +156,12 @@ fun AddImageGrid() { .background(Color(0xFFFFFFFF)) .drawBehind { drawRoundRect(color = Color(0xFF999999), style = stroke) + } + .clickable { + Intent(Intent.ACTION_PICK).apply { + type = "image/*" + pickImageLauncher.launch(this) + } }, ) { Image( @@ -152,6 +181,7 @@ fun AddImageGrid() { @OptIn(ExperimentalMaterial3Api::class) @Composable fun AdditionalPostItem() { + val model = NewPostViewModel val navController = LocalNavController.current var isShowLocationModal by remember { mutableStateOf(false) } fun onSelectLocationClick() { @@ -164,9 +194,16 @@ fun AdditionalPostItem() { }, containerColor = Color.White - ) { + ) { // Sheet content - SelectLocationModal() + SelectLocationModal( + onClose = { + isShowLocationModal = false + } + ) { + isShowLocationModal = false + model.searchPlaceAddressResult = it + } } } Column( @@ -180,7 +217,11 @@ fun AdditionalPostItem() { onSelectLocationClick() } ) { - Row( + model.searchPlaceAddressResult?.let { + SelectedLocation(it) { + model.searchPlaceAddressResult = null + } + } ?: Row( verticalAlignment = Alignment.CenterVertically ) { Image( @@ -197,12 +238,12 @@ fun AdditionalPostItem() { modifier = Modifier.size(24.dp) ) } - } Box( modifier = Modifier .fillMaxWidth() - .padding(vertical = 16.dp, horizontal = 24.dp).clickable { + .padding(vertical = 16.dp, horizontal = 24.dp) + .clickable { navController.navigate("EditModification") } ) { @@ -224,6 +265,41 @@ fun AdditionalPostItem() { ) } + } + } +} + +@Composable +fun SelectedLocation( + searchPlaceAddressResult: SearchPlaceAddressResult, + onRemoveLocation: () -> Unit +) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Column( + modifier = Modifier + .weight(1f) + .padding(end = 16.dp) + ) { + Text(searchPlaceAddressResult.name, fontWeight = FontWeight.Bold) + Text(searchPlaceAddressResult.address, color = Color(0xFF9a9a9a)) + } + Image( + painter = painterResource(id = R.drawable.rider_pro_close), + contentDescription = "Next", + modifier = Modifier + .size(24.dp) + .clickable { + onRemoveLocation() + } + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/NewPostViewModel.kt b/app/src/main/java/com/aiosman/riderpro/NewPostViewModel.kt new file mode 100644 index 0000000..8a2db51 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/NewPostViewModel.kt @@ -0,0 +1,11 @@ +package com.aiosman.riderpro + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel + +object NewPostViewModel : ViewModel() { + var textContent by mutableStateOf("") + var searchPlaceAddressResult by mutableStateOf(null) +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/SelectLocationModal.kt b/app/src/main/java/com/aiosman/riderpro/SelectLocationModal.kt index 4c7d906..7bb460b 100644 --- a/app/src/main/java/com/aiosman/riderpro/SelectLocationModal.kt +++ b/app/src/main/java/com/aiosman/riderpro/SelectLocationModal.kt @@ -1,7 +1,9 @@ package com.aiosman.riderpro +import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -24,15 +26,52 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.google.android.gms.common.api.ApiException +import com.google.android.libraries.places.api.Places +import com.google.android.libraries.places.api.model.Place +import com.google.android.libraries.places.api.net.PlacesClient +import com.google.android.libraries.places.api.net.SearchByTextRequest + +data class SearchPlaceAddressResult( + val name: String, + val address: String +) -@Preview @Composable -fun SelectLocationModal() { +fun SelectLocationModal(onClose:() -> Unit,onSelectedLocation: (SearchPlaceAddressResult) -> Unit) { + val context = LocalContext.current + var queryString by remember { mutableStateOf("") } + var searchPlaceAddressResults by remember { + mutableStateOf>( + emptyList() + ) + } + + fun searchAddrWithGoogleMap(query: String) { + val placesClient: PlacesClient = Places.createClient(context) + val placeFields: List = + listOf(Place.Field.ID, Place.Field.NAME, Place.Field.ADDRESS) + val request = SearchByTextRequest.newInstance(query, placeFields) + placesClient.searchByText(request) + .addOnSuccessListener { response -> + val place = response.places + searchPlaceAddressResults = place.map { + SearchPlaceAddressResult(it.name ?: "", it.address ?: "") + } + + }.addOnFailureListener { exception -> + if (exception is ApiException) { + Log.e("SelectLocationModal", "Place not found: ${exception.statusCode}") + } + } + } Column( modifier = Modifier .fillMaxSize() @@ -51,17 +90,27 @@ fun SelectLocationModal() { ) Text( "Cancel", - modifier = Modifier.align(Alignment.CenterEnd), + modifier = Modifier.align(Alignment.CenterEnd).clickable { + onClose() + }, fontSize = 16.sp ) } - LocationSearchTextInput() + LocationSearchTextInput(queryString, onQueryClick = { + searchAddrWithGoogleMap(queryString) + }) { + queryString = it + } LazyColumn( - modifier = Modifier.weight(1f).padding(top = 28.dp) + modifier = Modifier + .weight(1f) + .padding(top = 28.dp) ) { - item{ - repeat(20){ - LocationItem() + item { + for (searchPlaceAddressResult in searchPlaceAddressResults) { + LocationItem(searchPlaceAddressResult) { + onSelectedLocation(searchPlaceAddressResult) + } } } } @@ -70,8 +119,11 @@ fun SelectLocationModal() { } @Composable -fun LocationSearchTextInput() { - var text by remember { mutableStateOf("") } +fun LocationSearchTextInput( + value: String, + onQueryClick: () -> Unit, + onValueChange: (String) -> Unit +) { Box( modifier = Modifier .fillMaxWidth() @@ -81,17 +133,20 @@ fun LocationSearchTextInput() { ) { Row( modifier = Modifier - .fillMaxWidth().padding(horizontal = 12.dp), + .fillMaxWidth() + .padding(horizontal = 12.dp), verticalAlignment = Alignment.CenterVertically ) { Image( painter = painterResource(id = R.drawable.rider_pro_search_location), contentDescription = "Search", - modifier = Modifier.size(24.dp) + modifier = Modifier + .size(24.dp) + .clickable { onQueryClick() } ) Spacer(modifier = Modifier.width(8.dp)) - if (text.isEmpty()) { + if (value.isEmpty()) { Text( "search", modifier = Modifier.padding(vertical = 16.dp), @@ -99,8 +154,8 @@ fun LocationSearchTextInput() { ) } BasicTextField( - value = "", - onValueChange = {}, + value = value, + onValueChange = onValueChange, modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp) @@ -113,20 +168,28 @@ fun LocationSearchTextInput() { } @Composable -fun LocationItem(){ +fun LocationItem( + searchPlaceAddressResult: SearchPlaceAddressResult, + onLocationItemClick: () -> Unit = {} +) { Box( modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp) + .clickable { + onLocationItemClick() + } ) { Row( verticalAlignment = Alignment.CenterVertically, ) { Column( - modifier = Modifier.weight(1f).padding(end = 16.dp) + modifier = Modifier + .weight(1f) + .padding(end = 16.dp) ) { - Text("Location Name") - Text("Address", color = Color(0xFF9a9a9a)) + Text(searchPlaceAddressResult.name, fontWeight = FontWeight.Bold) + Text(searchPlaceAddressResult.address, color = Color(0xFF9a9a9a)) } Image( painter = painterResource(id = R.drawable.rider_pro_nav_next),