This commit is contained in:
2024-08-03 15:58:19 +08:00
parent b17ac76005
commit 2dc0ee3307
9 changed files with 269 additions and 16 deletions

View File

@@ -2,6 +2,7 @@ package com.aiosman.riderpro
import android.content.Context
import android.content.SharedPreferences
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
/**
* 持久化本地数据
@@ -12,10 +13,16 @@ object AppStore {
var token: String? = null
var rememberMe: Boolean = false
private lateinit var sharedPreferences: SharedPreferences
lateinit var googleSignInOptions: GoogleSignInOptions
fun init(context: Context) {
sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
this.loadData()
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("754277015802-uarf8br8k8gkpbj0t9g65bvkvit630q5.apps.googleusercontent.com") // Replace with your server's client ID
.requestEmail()
.build()
googleSignInOptions = gso
}
suspend fun saveData() {

View File

@@ -1,5 +1,6 @@
package com.aiosman.riderpro.ui
import ImageViewer
import ModificationListScreen
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
@@ -62,6 +63,7 @@ sealed class NavigationRoute(
data object UserAuth : NavigationRoute("UserAuth")
data object EmailSignUp : NavigationRoute("EmailSignUp")
data object AccountEdit : NavigationRoute("AccountEditScreen")
data object ImageViewer : NavigationRoute("ImageViewer")
}
@@ -171,6 +173,13 @@ fun NavigationController(
composable(route = NavigationRoute.AccountEdit.route) {
AccountEditScreen()
}
composable(route = NavigationRoute.ImageViewer.route) {
CompositionLocalProvider(
LocalAnimatedContentScope provides this,
) {
ImageViewer()
}
}
}

View File

@@ -4,8 +4,6 @@ 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.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -38,14 +36,12 @@ import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.data.TestUserServiceImpl
import com.aiosman.riderpro.data.UserService
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AccountEditScreen() {
val userService: UserService = TestUserServiceImpl()
val accountService: AccountService = TestAccountServiceImpl()
var name by remember { mutableStateOf("") }

View File

@@ -0,0 +1,11 @@
package com.aiosman.riderpro.ui.imageviewer
object ImageViewerViewModel {
var imageList = mutableListOf<String>()
var initialIndex = 0
fun asNew(images: List<String>, index: Int = 0) {
imageList.clear()
imageList.addAll(images)
initialIndex = index
}
}

View File

@@ -0,0 +1,74 @@
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import coil.compose.AsyncImage
import com.aiosman.riderpro.LocalAnimatedContentScope
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.LocalSharedTransitionScope
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import net.engawapg.lib.zoomable.rememberZoomState
import net.engawapg.lib.zoomable.zoomable
@OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class)
@Composable
fun ImageViewer() {
val model = ImageViewerViewModel
val images = model.imageList
val pagerState = rememberPagerState(pageCount = { images.size }, initialPage = model.initialIndex)
val systemUiController = rememberSystemUiController()
val navController = LocalNavController.current
val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedVisibilityScope = LocalAnimatedContentScope.current
LaunchedEffect(Unit) {
systemUiController.setStatusBarColor(Color.Black)
systemUiController.setNavigationBarColor(Color.Black)
}
StatusBarMaskLayout(
modifier = Modifier.background(Color.Black),
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
) {
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize()
) { page ->
val zoomState = rememberZoomState()
with(sharedTransitionScope) {
AsyncImage(
images[page],
contentDescription = null,
modifier = Modifier.sharedElement(
rememberSharedContentState(key = images[page]),
animatedVisibilityScope = animatedVisibilityScope
)
.fillMaxSize()
.zoomable(
zoomState = zoomState,
onTap = {
navController.popBackStack()
}
),
contentScale = ContentScale.Fit,
)
}
}
}
}
}

View File

@@ -1,5 +1,9 @@
package com.aiosman.riderpro.ui.login
import android.app.Activity
import android.util.Log
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.layout.Box
@@ -20,18 +24,49 @@ 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.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.tasks.Task
@Composable
fun SignupScreen() {
val navController = LocalNavController.current
val context = LocalContext.current
val googleSignInClient = GoogleSignIn.getClient(context, AppStore.googleSignInOptions)
fun handleSignInResult(
task: Task<GoogleSignInAccount>,
onSignInSuccess: (GoogleSignInAccount) -> Unit
) {
try {
val account = task.getResult(ApiException::class.java)
onSignInSuccess(account)
} catch (e: ApiException) {
// Handle sign-in failure
}
}
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = { result ->
if (result.resultCode == Activity.RESULT_OK) {
val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
handleSignInResult(task) {account ->
// Handle sign-in success
Log.d("SignupScreen", "handleSignInResult: $account")
}
}
}
)
Scaffold(
modifier = Modifier
.fillMaxSize()
@@ -126,7 +161,10 @@ fun SignupScreen() {
},
text = "CONTINUE WITH GOOGLE".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_white_bg
)
) {
val signInIntent = googleSignInClient.signInIntent
launcher.launch(signInIntent)
}
Spacer(modifier = Modifier.height(16.dp))
Box(
modifier = Modifier

View File

@@ -70,7 +70,9 @@ import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.map
import coil.compose.AsyncImage
import com.aiosman.riderpro.LocalAnimatedContentScope
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.LocalSharedTransitionScope
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountProfile
import com.aiosman.riderpro.data.AccountService
@@ -87,6 +89,7 @@ import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
import com.aiosman.riderpro.ui.composables.EditCommentBottomModal
import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel
import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController
@@ -332,28 +335,43 @@ fun Header(accountProfile: AccountProfile?) {
}
@OptIn(ExperimentalFoundationApi::class)
@OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class)
@Composable
fun PostImageView(
postId: String,
images: List<String>,
) {
val pagerState = rememberPagerState(pageCount = { images.size })
val navController = LocalNavController.current
val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedVisibilityScope = LocalAnimatedContentScope.current
Column {
HorizontalPager(
state = pagerState,
modifier = Modifier
.weight(1f)
.fillMaxWidth(),
.fillMaxWidth().background(Color.Black),
) { page ->
val image = images[page]
AsyncImage(
image,
contentDescription = "Image",
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxSize()
)
with(sharedTransitionScope) {
AsyncImage(
image,
contentDescription = "Image",
contentScale = ContentScale.Fit,
modifier = Modifier
.sharedElement(
rememberSharedContentState(key = image),
animatedVisibilityScope = animatedVisibilityScope
)
.fillMaxSize()
.noRippleClickable {
ImageViewerViewModel.asNew(images, page)
navController.navigate(
NavigationRoute.ImageViewer.route
)
}
)
}
}
// Indicator container
@@ -547,7 +565,11 @@ fun BottomNavigationBar(
onClick = {
onLikeClick()
}) {
Icon(Icons.Filled.Favorite, contentDescription = "like", tint = if (momentItem?.liked == true) Color.Red else Color.Gray)
Icon(
Icons.Filled.Favorite,
contentDescription = "like",
tint = if (momentItem?.liked == true) Color.Red else Color.Gray
)
}
Text(text = momentItem?.likeCount.toString())
IconButton(

View File

@@ -0,0 +1,67 @@
package com.aiosman.riderpro.ui.search
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
@Composable
fun SearchScreen() {
Scaffold { paddingValues ->
var tabIndex by remember { mutableStateOf(0) }
Column(
modifier = Modifier
.fillMaxWidth()
.padding(paddingValues)
) {
TextField(
value = "",
onValueChange = {},
label = { Text("Search") },
modifier = Modifier.fillMaxWidth(),
trailingIcon = {
Icon(
imageVector = Icons.Default.Search,
contentDescription = null
)
}
)
TabRow(selectedTabIndex = tabIndex) {
Tab(text = { Text("Post") },
selected = tabIndex == 0,
onClick = { tabIndex = 0 }
)
Tab(text = { Text("User") },
selected = tabIndex == 1,
onClick = { tabIndex = 1 }
)
}
when (tabIndex) {
0 -> SearchPostResults()
1 -> SearchUserResults()
}
}
}
}
@Composable
fun SearchPostResults() {
Text("Post Results")
}
@Composable
fun SearchUserResults(){
Text("User Results")
}