diff --git a/.github/workflows/debug_builder.yml b/.github/workflows/debug_builder.yml new file mode 100644 index 00000000..9ad95f36 --- /dev/null +++ b/.github/workflows/debug_builder.yml @@ -0,0 +1,84 @@ +#name: TeumTeum Push Builder +# +#on: +# push: +# branches: [ main ] +# +#defaults: +# run: +# shell: bash +# working-directory: . +# +#jobs: +# build: +# name: APK Builder When Push +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 +# +# - name: Gradle cache +# uses: actions/cache@v2 +# with: +# path: | +# ~/.gradle/caches +# ~/.gradle/wrapper +# key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} +# restore-keys: | +# ${{ runner.os }}-gradle- +# - name: set up JDK 17 +# uses: actions/setup-java@v1 +# with: +# java-version: 17 +# +# - name: Change gradlew permissions +# run: chmod +x ./gradlew +# +# - name: Create Local Properties +# run: touch local.properties +# +# - name: Access Local Properties +# env: +# base_url: ${{ secrets.BASE_URL }} +# image_url: ${{ secrets.IMAGE_URL }} +# kakao_redirect_url: ${{ secrets.KAKAO_REDIRECT_URL }} +# naver_redirect_url: ${{ secrets.KAKAO_REDIRECT_URL }} +# kakao_api_key: ${{ secrets.KAKAO_API_KEY }} +# naver_api_key: ${{ secrets.NAVER_API_KEY }} +# run: | +# echo base.url=\"$base_url\" >> local.properties +# echo image.url=\"$image_url\" >> local.properties +# echo kakao.redirect=\"$kakao_redirect_url\" >> local.properties +# echo naver.redirect=\"$naver_redirect_url\" >> local.properties +# echo kakao.key=\"$kakao_api_key\" >> local.properties +# echo naver.key=\"$naver_api_key\" >> local.properties +# +# - name: Access Firebase Service +# run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > ./app/google-services.json +# +# - name: Build debug APK +# run: ./gradlew assembleDebug --stacktrace +# +# - name: On Success +# if: ${{ success() }} +# uses: MeilCli/slack-upload-file@v1 +# with: +# slack_token: ${{ secrets.SLACK_BOT_TOKEN}} +# channels: ${{ secrets.SLACK_CHANNEL_ID}} +# file_path: 'app/build/outputs/apk/debug/app-debug.apk' +# file_name: 'TeumTeum.apk' +# file_type: 'apk' +# initial_comment: '๐ŸŽ‰ TeumTeum์ด ์Šฌ๋ž™์œผ๋กœ ๋“ค์–ด์™”์Šต๋‹ˆ๋‹ค.' +# +# - name: On Failed, Notify in Slack +# if: ${{ failure() }} +# uses: rtCamp/action-slack-notify@v2 +# env: +# SLACK_COLOR: '#ff0000' +# SLACK_ICON: https://play-lh.googleusercontent.com/jUeDnP2wd29y48wolu5a8j08PX3Zt-wsftTVuSR8gYgHI00sq7Zsq2jWx1icTdsISw=w240-h480-rw +# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} +# SLACK_TITLE: 'TEUMTEUM/Android debug build FailโŒ' +# MSG_MINIMAL: true +# SLACK_USERNAME: TEUMTEUM_ANDROID +# SLACK_MESSAGE: 'APK ์ƒ์„ฑ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”' +# \ No newline at end of file diff --git a/README.md b/README.md index 186a3570..3f0fbcf5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,31 @@ - # TeumTeum-Android Repository + -![2046](https://github.com/depromeet/TeumTeum-Android/assets/89737271/6a51c5f5-f809-4a2d-a8d3-684b82e80afc) +# Teum-Teum + +> ์‚ฌ๋žŒ ์‚ฌ์ด์˜ **ํ‹ˆ**์„ ์ด์–ด์ฃผ๋Š” IT ์ปค๋ฆฌ์–ด ๋„คํŠธ์›Œํ‚น ์„œ๋น„์Šค `repo:server` + +![Build](https://img.shields.io/github/actions/workflow/status/depromeet/teum-teum-server/integration-tester.yml?branch=develop&style=for-the-badge&logo=github&logoColor=white&color=36B2FF) ![](https://img.shields.io/sonar/test_success_density/depromeet_teum-teum-server?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonar&logoColor=white&color=36B2FF) ![](https://img.shields.io/sonar/quality_gate/depromeet_teum-teum-server/develop?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonar&logoColor=white&color=36B2FF) ![](https://img.shields.io/github/v/release/depromeet/teum-teum-server?include_prereleases&style=for-the-badge&color=36B2FF) + +[![download](https://img.shields.io/badge/playstore-download-brightgreen?style=social&logo=googleplay&color=36B2FF)](https://play.google.com/store/apps/details?id=com.teumteum.teumteum&pcampaignid=web_share) [![instagram](https://img.shields.io/badge/instagram-click-brightgreen?style=social&logo=instagram&color=36B2FF)](https://www.instagram.com/teumteum_official/) [![behance](https://img.shields.io/badge/behance-click-brightgreen?style=social&logo=behance&color=36B2FF)](https://www.behance.net/gallery/191510163/%08TEUMTEUM-IT-Career-Growth-Networking-Service) + +--- + +

+ MOBILE_1 + MOBILE_2 +

+

+ MOBILE_3 + MOBILE_4 +

+

+ MOBILE_5 + MOBILE_6 +

+

+ MOBILE_7 + MOBILE_8 +


@@ -10,3 +35,117 @@ ||||| |**๋ชจ์ž„ ์ฐธ์—ฌ & ์œ ์ € ๋ฆฌ๋ทฐ**|**๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ ์ฐพ๊ธฐ**|**๋ชจ์ž„ ์ƒ์„ฑ & ๋งˆ์ดํŽ˜์ด์ง€**|**๋กœ๊ทธ์ธ & ์ž๊ธฐ์†Œ๊ฐœ ์นด๋“œ**| +
+ +## Tech Stack โš’๏ธ +- Clean Architecture +- Multi-Module + +- MVVM +- Repository Pattern + +- Compose + XML +- Hilt + +- Coroutine +- Version Catalog + +- Kotlin - Flow +- GitHub Action CI / CD + +
+ +## System Architecture ๐Ÿ’ป + +### Architecture (with Data flow) +![image](https://github.com/depromeet/TeumTeum-Android/assets/100370200/b914bf6d-d052-46be-ba05-a841673f38c0) + + +### MODULE +``` +๐Ÿ—ƒ๏ธapp + โ”ฃ ๐Ÿ“‚di + โ”ฃ ๐Ÿ“‚presentation + โ”ฃ ๐Ÿ“‚util +๐Ÿ—ƒ๏ธbuild-logic + โ”ฃ ๐Ÿ“‚convention +๐Ÿ—ƒ๏ธcore + โ”ฃ ๐Ÿ“‚base +๐Ÿ—ƒ๏ธdata + โ”ฃ ๐Ÿ“‚datasource + โ”ฃ ๐Ÿ“‚local + โ”ฃ ๐Ÿ“‚model + โ”ƒ โ”ฃ ๐Ÿ“‚response + โ”ƒ โ”ฃ ๐Ÿ“‚request + โ”ฃ ๐Ÿ“‚repository + โ”ฃ ๐Ÿ“‚remote + โ”ƒ โ”ฃ ๐Ÿ“‚interceptor + โ”ƒ โ”ฃ ๐Ÿ“‚service + โ”ฃ ๐Ÿ“‚util +๐Ÿ—ƒ๏ธdomain + โ”ฃ ๐Ÿ“‚entity + โ”ฃ ๐Ÿ“‚repository +``` + +
+ +## ํ‹ˆํ‹ˆ์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค ๐ŸŽ‰ + +ํ‹ˆํ‹ˆ์€ IT ์—…๊ณ„์—์„œ ์ปค๋ฆฌ์–ด ์„ฑ์žฅ์„ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๋Š” '๊ฐ“์ƒ๋Ÿฌ'๋“ค์„ ๋งŒ๋‚  ์ˆ˜ ์žˆ๋Š” ๋„คํŠธ์›Œํ‚น ํ”Œ๋žซํผ์ด์—์š”. +ํ•จ๊ป˜ ์Šคํ„ฐ๋””๋ฅผ ํ•˜๊ฑฐ๋‚˜ ๋ชจ์—ฌ์„œ ๊ฐ์ž ์ž‘์—…์„ ํ•˜๋ฉฐ ๋‹ค์–‘ํ•œ ๋„คํŠธ์›Œํ‚น ํ™œ๋™์„ ํ•  ์ˆ˜ ์žˆ์–ด์š”. + +์ฒ˜์Œ ๋งŒ๋‚˜๋Š” ์‚ฌ์ด๋ผ ์–ด์ƒ‰ํ•จ์ด ๋Š๊ปด์งˆ ๋•Œ๋Š” '์นœํ•ด์ง€๊ธฐ' ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•ด ๊ด€์‹ฌ์‚ฌ๋ฅผ ํŒŒ์•…ํ•˜๊ณ , +ํ•จ๊ป˜ ์ฆ๊ฒ๊ฒŒ ๋Œ€ํ™”๋ฅผ ๋‚˜๋ˆ„๋ฉฐ ์„œ๋กœ์˜ ํ‹ˆ์„ ์ฑ„์›Œ ๊ฐ€๊นŒ์›Œ์งˆ ์ˆ˜ ์žˆ์–ด์š”! + +IT ์ง๊ตฐ์˜ ๋‹ค์–‘ํ•œ ๊ฐœ์„ฑ์„ ์ง€๋‹Œ ์‚ฌ๋žŒ๋“ค๊ณผ ๋„คํŠธ์›Œํ‚นํ•˜๋ฉฐ ์ปค๋ฆฌ์–ด๋ฅผ ์„ฑ์žฅ์‹œ์ผœ ๋ณด๋Š” ๊ฒƒ์€ ์–ด๋–จ๊นŒ์š”? + +
+ +## ํ‹ˆํ‹ˆ์„ ์ฒ˜์Œ ์‚ฌ์šฉํ•˜์‹œ๋‚˜์š”? ๐Ÿ˜Ž +![Untitled](https://github.com/depromeet/TeumTeum-Android/assets/100370200/7ce79833-06aa-40a3-afd1-18f0dc37601b) + +### โ˜๏ธย Step 01 ์†Œ๊ฐœ์„œ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ฐ„ํŽธํ•˜๊ฒŒ ์†Œ๊ฐœํ•ด ๋ณด์„ธ์š” +- ๊ด€์‹ฌ์‚ฌ์™€ ๋ชฉํ‘œ๊ฐ€ ๋‹ด๊ฒจ ์žˆ๋Š” ์†Œ๊ฐœ์„œ๋ฅผ ๋งŒ๋“ค์–ด์š”. +- ๋ชจ์ž„์— ์ฐธ์—ฌํ•  ๋•Œ ์†Œ๊ฐœ์„œ๋กœ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ž์‹ ์„ ์†Œ๊ฐœ ํ•  ์ˆ˜ ์žˆ์–ด์š”. + +
+ +![Untitled2](https://github.com/depromeet/TeumTeum-Android/assets/100370200/4d716950-d3c8-47b0-bef5-890396188598) + +### โœŒ๏ธย Step 02 ์›ํ•˜๋Š” ๋ชจ์ž„์— ์ฐธ์—ฌํ•ด ๋ณด์„ธ์š” +- ํ‹ˆํ‹ˆ์—์„œ๋Š” ์Šคํ„ฐ๋””๋ถ€ํ„ฐ ๋ชจ๊ฐ์ž‘๊นŒ์ง€ ๋‹ค์–‘ํ•œ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋ชจ์ž„์— ์ฐธ์—ฌํ•  ์ˆ˜ ์žˆ์–ด์š”. +- ์ฐธ์—ฌ์ž๋“ค์˜ ์†Œ๊ฐœ์„œ๋ฅผ ๋ฏธ๋ฆฌ ํ™•์ธํ•˜๊ณ , ๋ฏฟ์„ ์ˆ˜ ์žˆ๋Š” ๋ชจ์ž„์„ ์‹œ์ž‘ํ•ด ๋ณด์„ธ์š”. + +
+ +![Untitled3](https://github.com/depromeet/TeumTeum-Android/assets/100370200/a455a546-b573-4470-ba27-80fb49184cc9) + +### ๐ŸคŸย Step 03 ํ•จ๊ป˜ ์„ฑ์žฅํ•  ๊ทผ์ฒ˜์˜ ์นœ๊ตฌ๋ฅผ ์ฐพ์•„๋ด์š” +- ๋‚ด๊ฐ€ ์‚ฌ๋Š” ๊ณณ ๊ทผ์ฒ˜, ํ˜น์€ ํšŒ์‚ฌ ๊ทผ์ฒ˜์—์„œ ์นœ๊ตฌ๋ฅผ ๋งŒ๋‚  ์ˆ˜ ์žˆ์–ด์š”. +- ๋‚ด ์ฃผ๋ณ€์˜ ์นœ๊ตฌ์™€ ํ•จ๊ป˜ ์ปค๋ฆฌ์–ด ์„ฑ์žฅ์„ ์œ„ํ•œ ๋ชจ์ž„์„ ์‹œ์ž‘ํ•ด ๋ณด์„ธ์š”. + +
+ +![Untitled4](https://github.com/depromeet/TeumTeum-Android/assets/100370200/97252e07-9822-4c40-abd0-dcb153524c0c) + +### ๐ŸคŸ Step 04 ์„œ๋กœ์˜ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ฐœ๊ฒฌํ•ด์š” +- ์†Œ๊ฐœ์„œ์— ์ž‘์„ฑํ•œ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ชจ์ž„ ์ฐธ์—ฌ์ž๋“ค์˜ ๊ด€์‹ฌ์‚ฌ๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”. +- ๊ธฐ๊ธฐ๋ฅผ ํ”๋“ค๋ฉด ๋ชจ์ž„ ์ฐธ์—ฌ์ž๋“ค์˜ ๋‹ค์–‘ํ•œ ๊ด€์‹ฌ์‚ฌ ์‚ฌ์ด์˜ ํ‹ˆ์„ ์ฑ„์šธ ์ˆ˜ ์žˆ์–ด์š”. +- chat GPT๊ฐ€ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ณตํ†ต์ ์œผ๋กœ ๊ด€์‹ฌ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ฃผ์ œ๋ฅผ ์•Œ๋ ค์ค„๊ฑฐ์—์š”. + + +
+ +![Untitled5](https://github.com/depromeet/TeumTeum-Android/assets/100370200/432f3ec9-32d1-4749-badb-7a49cec6ec12) + +### ๐Ÿ–– Step 05 ๋ฐธ๋Ÿฐ์Šค ๊ฒŒ์ž„์œผ๋กœ ์นœํ•ด์ ธ์š” +- ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ์™€ ๊ด€๋ จ๋œ ๋‹ค์–‘ํ•œ ๋Œ€ํ™” ์ฃผ์ œ๋ฅผ ํ™•์ธํ•˜๊ณ , ๋Œ€ํ™”๋ฅผ ์‹œ์ž‘ํ•ด๋ด์š”. +- ์–ด์ƒ‰ํ•œ ์ˆœ๊ฐ„๋„ ์ž ์‹œ, ๋ฐธ๋Ÿฐ์Šค ๊ฒŒ์ž„์„ ํ†ตํ•ด ๋น ๋ฅด๊ฒŒ ์นœํ•ด์งˆ ์ˆ˜ ์žˆ์–ด์š”. + +
+ +![Untitled6](https://github.com/depromeet/TeumTeum-Android/assets/100370200/1a5d824f-5231-419f-a9ed-813128b247a0) + +### ๐Ÿ–– Step 06 ๋ชจ์ž„ ํ›„ ๋ฆฌ๋ทฐ๋ฅผ ํ†ตํ•ด ๋” ๋‚˜์€ ๋„คํŠธ์›Œํ‚น ํ™˜๊ฒฝ์„ ๋งŒ๋“ค์–ด๊ฐ€์š” +- ๋ชจ์ž„์ด ๋๋‚œ ํ›„ ๋‹ค์Œ๋‚ ์— ์œ ์ € ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”. +- ์œ ์ € ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๋” ๋‚˜์€ ๋„คํŠธ์›Œํ‚น ํ™˜๊ฒฝ์„ ๋งŒ๋“ค์–ด๋ด์š”. diff --git a/app/src/main/java/com/teumteum/teumteum/MyApp.kt b/app/src/main/java/com/teumteum/teumteum/MyApp.kt index d752b143..9f2f9e16 100644 --- a/app/src/main/java/com/teumteum/teumteum/MyApp.kt +++ b/app/src/main/java/com/teumteum/teumteum/MyApp.kt @@ -2,12 +2,15 @@ package com.teumteum.teumteum import android.app.Application import android.content.Context -import androidx.appcompat.app.AppCompatDelegate +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.OnLifecycleEvent +import androidx.lifecycle.ProcessLifecycleOwner import dagger.hilt.android.HiltAndroidApp import timber.log.Timber @HiltAndroidApp -class MyApp : Application() { +class MyApp : Application(), LifecycleObserver { override fun onCreate() { super.onCreate() @@ -18,9 +21,17 @@ class MyApp : Application() { } setUpFlipper() appContext = applicationContext + ProcessLifecycleOwner.get().lifecycle.addObserver(this) } + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) + fun onAppBackgrounded() { isForeground = false } + + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + fun onAppForegrounded() { isForeground = true} + companion object { lateinit var appContext: Context + var isForeground = false } } diff --git a/app/src/main/java/com/teumteum/teumteum/config/TeumMessagingService.kt b/app/src/main/java/com/teumteum/teumteum/config/TeumMessagingService.kt index ce2f30a4..abf00aee 100644 --- a/app/src/main/java/com/teumteum/teumteum/config/TeumMessagingService.kt +++ b/app/src/main/java/com/teumteum/teumteum/config/TeumMessagingService.kt @@ -13,6 +13,7 @@ import com.teumteum.data.model.request.toDeviceToken import com.teumteum.data.service.UserService import com.teumteum.domain.TeumTeumDataStore import com.teumteum.domain.entity.Message +import com.teumteum.domain.repository.UserRepository import com.teumteum.teumteum.R import com.teumteum.teumteum.presentation.splash.SplashActivity import dagger.hilt.android.AndroidEntryPoint @@ -30,6 +31,9 @@ class TeumMessagingService : FirebaseMessagingService() { @Inject lateinit var userService: UserService + @Inject + lateinit var userRepository: UserRepository + override fun onNewToken(token: String) { super.onNewToken(token) @@ -51,22 +55,25 @@ class TeumMessagingService : FirebaseMessagingService() { } } - override fun onMessageReceived(message: RemoteMessage) { - super.onMessageReceived(message) + override fun handleIntent(intent: Intent?) { + super.handleIntent(intent) if (dataStore.onNotification) { if (dataStore.isLogin) { - val alertMessage = Message("", "", "") - if (message.data.isNotEmpty()) { - alertMessage.title = message.notification?.title.toString() - alertMessage.body = message.notification?.body.toString() - alertMessage.type = message.data["type"].toString() - } - if (alertMessage.type == END_MEETING) { - alertMessage.meetingId = message.data["meetingId"]?.toLong() - alertMessage.participants = message.data["participants"]?.toList()?.map { it.digitToInt() } + intent?.let { + val alertMessage = Message("", "", "") + alertMessage.title = intent.getStringExtra("title").toString() + alertMessage.body = intent.getStringExtra("body").toString() + alertMessage.type = intent.getStringExtra("type").toString() + if (alertMessage.type == END_MEETING) { + alertMessage.meetingId = intent.getStringExtra("meetingId")?.toLong() + alertMessage.participants = + intent.getStringExtra("participants")?.split(",")?.map { it.toInt() } + val userId = userRepository.getUserInfo()?.id?.toInt() + if (alertMessage.participants?.contains(userId) == true && alertMessage.participants?.size!! > 2) + sendNotificationAlarm(alertMessage) + } else if (alertMessage.title.isNotEmpty()) sendNotificationAlarm(alertMessage) } - if (alertMessage.title.isNotEmpty()) sendNotificationAlarm(alertMessage) } } } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewFriendDetailFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewFriendDetailFragment.kt index 5168e37a..1154e1c8 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewFriendDetailFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewFriendDetailFragment.kt @@ -48,8 +48,8 @@ class ReviewFriendDetailFragment : private fun initClick() { val friendDetail = ReviewFriend(id, characterId, name, job) binding.btnReview.setOnSingleClickListener { + viewModel.addSelectDetailFriendList(friendDetail) if (viewModel.currentFriendIndex < viewModel.selectFriendList.size) { - viewModel.addSelectDetailFriendList(friendDetail) (requireActivity() as? ReviewActivity)?.nextFriendDetailFragment() } else { viewModel.postRegisterReview() diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewViewModel.kt index edd1ca6d..0009dd5e 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewViewModel.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/review/ReviewViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.teumteum.domain.entity.ReviewFriend import com.teumteum.domain.repository.GroupRepository +import com.teumteum.domain.repository.UserRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow @@ -12,13 +13,14 @@ import kotlinx.coroutines.launch @HiltViewModel class ReviewViewModel @Inject constructor( - private val repository: GroupRepository + private val repository: GroupRepository, + private val userRepository: UserRepository ) : ViewModel() { private var _selectFriendList = listOf() val selectFriendList get() = _selectFriendList private var _selectDetailFriendList = mutableListOf() - val selectDetailFriendList get() = _selectFriendList + val selectDetailFriendList get() = _selectDetailFriendList var meetingId: Long? = null @@ -34,15 +36,23 @@ class ReviewViewModel @Inject constructor( } fun addSelectDetailFriendList(selectFriendDetail: ReviewFriend) { + _selectDetailFriendList.removeAll { it.id == selectFriendDetail.id } _selectDetailFriendList.add(selectFriendDetail) } + private fun filterReviewFriendList(list: List): List { + val friendList = list.toMutableList() + val myUserId = userRepository.getUserInfo()?.id + friendList.removeAll { it.id == myUserId } + return friendList + } + fun getReviewFriendList() { meetingId?.let { id -> viewModelScope.launch { repository.getReviewFriendList(id) - .onSuccess { - _moimFriendList.value = it + .onSuccess { list -> + _moimFriendList.value = filterReviewFriendList(list) } } } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/mypage/recommend/RecommendScreen.kt b/app/src/main/java/com/teumteum/teumteum/presentation/mypage/recommend/RecommendScreen.kt index 8d76e7f5..7aea4e9d 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/mypage/recommend/RecommendScreen.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/mypage/recommend/RecommendScreen.kt @@ -20,7 +20,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -40,7 +39,6 @@ import com.teumteum.teumteum.presentation.mypage.setting.viewModel.MyPageViewMod import com.teumteum.teumteum.presentation.mypage.setting.viewModel.Recommend import com.teumteum.teumteum.presentation.mypage.setting.viewModel.RecommendDetailViewModel import com.teumteum.teumteum.presentation.mypage.setting.viewModel.UserInfoUiState -import com.teumteum.teumteum.presentation.mypage.setting.viewModel.SettingViewModel import com.teumteum.teumteum.presentation.mypage.setting.viewModel.toRecommend import com.teumteum.teumteum.util.SignupUtils.CHARACTER_CARD_FRIEND @@ -127,6 +125,7 @@ fun RecommendItem(recommend: Recommend, myPageViewModel: MyPageViewModel, navCon verticalAlignment = Alignment.CenterVertically ) { RecommendRow(recommend = recommend, list= CHARACTER_CARD_FRIEND) + RecommendRow(recommend = recommend, list= SignupUtils.CHARACTER_FRIEND_LIST) recommend.jobName?.let { Text( text = it, diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/mypage/setting/viewModel/MyPageViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/mypage/setting/viewModel/MyPageViewModel.kt index f0deee29..dfd31b98 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/mypage/setting/viewModel/MyPageViewModel.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/mypage/setting/viewModel/MyPageViewModel.kt @@ -125,6 +125,7 @@ class MyPageViewModel @Inject constructor( } } } + fun userInfoToFrontCard(userInfo: UserInfo, characterList: HashMap): FrontCard { return FrontCard( name = userInfo.name, diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/signup/complete/CardCompleteFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/signup/complete/CardCompleteFragment.kt index 9d853b57..3e1d0451 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/signup/complete/CardCompleteFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/signup/complete/CardCompleteFragment.kt @@ -16,6 +16,7 @@ import com.teumteum.teumteum.util.SignupUtils.CHARACTER_CARD_LIST_BACK import com.teumteum.teumteum.util.SignupUtils.STATUS_STUDENT import com.teumteum.teumteum.util.SignupUtils.STATUS_TRAINEE import com.teumteum.teumteum.util.SignupUtils.STATUS_WORKER +import com.teumteum.teumteum.util.custom.view.model.BackCard import com.teumteum.teumteum.util.custom.view.model.FrontCard import com.teumteum.teumteum.util.custom.view.model.Interest import dagger.hilt.android.AndroidEntryPoint @@ -60,9 +61,10 @@ class CardCompleteFragment for (i in interestSelf.value) { interests.add(Interest(i)) } + + val bc = BackCard(goalContent = goalText.value, characterResId = CHARACTER_CARD_LIST_BACK[characterId.value]) + binding.cardviewBack.getInstance(bc) binding.cardviewBack.apply { - tvGoalContent.text = goalText.value - CHARACTER_CARD_LIST_BACK[characterId.value]?.let { ivCharacter.setImageResource(it) } submitInterestList(interests) isModify = false setIsModifyDetail(false) diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/signup/fix/CardFixFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/signup/fix/CardFixFragment.kt index 404b615a..4a63108b 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/signup/fix/CardFixFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/signup/fix/CardFixFragment.kt @@ -73,11 +73,13 @@ class CardFixFragment for (i in interestSelf.value) { interests.add(Interest(i)) } + + val bc = BackCard(goalContent = goalText.value, characterResId = SignupUtils.CHARACTER_CARD_LIST_BACK[characterId.value]) + binding.cardviewBack.getInstance(bc) binding.cardviewBack.apply { - setIsModifyDetail(true) - tvGoalContent.text = goalText.value - SignupUtils.CHARACTER_CARD_LIST_BACK[characterId.value]?.let { ivCharacter.setImageResource(it) } submitInterestList(interests) + isModify = false + setIsModifyDetail(true) } } } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/signup/name/GetNameFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/signup/name/GetNameFragment.kt index 8dec9030..c69f08be 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/signup/name/GetNameFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/signup/name/GetNameFragment.kt @@ -2,6 +2,7 @@ package com.teumteum.teumteum.presentation.signup.name import android.os.Bundle import android.text.Editable +import android.text.InputFilter import android.text.TextWatcher import android.view.View import androidx.fragment.app.activityViewModels @@ -26,6 +27,7 @@ class GetNameFragment binding.vm = viewModel binding.lifecycleOwner = this + binding.etName.filters = arrayOf(filterAlphaNumSpace) setTextChangedListener() checkValidinput() } @@ -44,18 +46,31 @@ class GetNameFragment }) } + private var filterAlphaNumSpace = InputFilter { source, _, _, _, _, _ -> + val ps = Pattern.compile(REGEX_NAME_PATTERN_WRITING) + if (!ps.matcher(source).matches()) { + "" + } else source + } + private fun checkValidinput() { lifecycleScope.launch { viewModel.userName.collect { userName -> - if (Pattern.matches(REGEX_NAME_PATTERN, userName) && userName.trim().length >= 2) + if (Pattern.matches(REGEX_NAME_PATTERN_SUBMIT, userName) && userName.trim().length >= 2) { (activity as SignUpActivity).activateNextButton() - else + binding.tvCaption.visibility = View.INVISIBLE + } + else { (activity as SignUpActivity).disableNextButton() + if (userName.isNotBlank()) binding.tvCaption.visibility = View.VISIBLE + else binding.tvCaption.visibility = View.INVISIBLE + } } } } companion object { - private const val REGEX_NAME_PATTERN = "^([๊ฐ€-ํžฃ]*)\$" + private const val REGEX_NAME_PATTERN_SUBMIT = "^([๊ฐ€-ํžฃ]*)\$" + private const val REGEX_NAME_PATTERN_WRITING = "^[ใ„ฑ-ใ…ฃ๊ฐ€-ํžฃ]+$" } } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/splash/SplashActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/splash/SplashActivity.kt index a21263b4..79b234e7 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/splash/SplashActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/splash/SplashActivity.kt @@ -11,6 +11,7 @@ import androidx.lifecycle.lifecycleScope import com.teumteum.base.BindingActivity import com.teumteum.base.util.extension.defaultSnackBar import com.teumteum.domain.entity.Message +import com.teumteum.teumteum.MyApp.Companion.isForeground import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.ActivitySplashBinding import com.teumteum.teumteum.presentation.MainActivity @@ -32,6 +33,7 @@ class SplashActivity isFromAlarm = intent.getBooleanExtra(IS_FROM_ALARM, false) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) getMessage() + if (isForeground) startHomeScreen() checkNetwork() } diff --git a/app/src/main/java/com/teumteum/teumteum/util/ResMapper.kt b/app/src/main/java/com/teumteum/teumteum/util/ResMapper.kt index 2f6269dc..0e2f2f38 100644 --- a/app/src/main/java/com/teumteum/teumteum/util/ResMapper.kt +++ b/app/src/main/java/com/teumteum/teumteum/util/ResMapper.kt @@ -60,6 +60,23 @@ object ResMapper { } } + fun getColorByBackCardCharacterDrawble(context: Context, characterResId: Int): Int { + return when (characterResId) { + R.drawable.ic_card_back_ghost -> getColorByCharacterId(context, 0) + R.drawable.ic_card_back_star -> getColorByCharacterId(context, 1) + R.drawable.ic_card_back_bear -> getColorByCharacterId(context, 2) + R.drawable.ic_card_back_raccon -> getColorByCharacterId(context, 3) + R.drawable.ic_card_back_cat -> getColorByCharacterId(context, 4) + R.drawable.ic_card_back_rabbit -> getColorByCharacterId(context, 5) + R.drawable.ic_card_back_fox -> getColorByCharacterId(context, 6) + R.drawable.ic_card_back_water -> getColorByCharacterId(context, 7) + R.drawable.ic_card_back_penguin -> getColorByCharacterId(context, 8) + R.drawable.ic_card_back_dog -> getColorByCharacterId(context, 9) + R.drawable.ic_card_back_mouse -> getColorByCharacterId(context, 10) + R.drawable.ic_card_back_panda -> getColorByCharacterId(context, 11) + else -> getColorByCharacterId(context, 0) + } + } fun getColorByCharacterId(context: Context, characterId: Int): Int { return when (characterId) { diff --git a/app/src/main/java/com/teumteum/teumteum/util/SignupUtils.kt b/app/src/main/java/com/teumteum/teumteum/util/SignupUtils.kt index 0812c302..dc570eb5 100644 --- a/app/src/main/java/com/teumteum/teumteum/util/SignupUtils.kt +++ b/app/src/main/java/com/teumteum/teumteum/util/SignupUtils.kt @@ -52,6 +52,21 @@ object SignupUtils { 11 to R.drawable.ic_panda ) + val CHARACTER_FRIEND_LIST: HashMap = hashMapOf( + 0 to R.drawable.ic_ghost, + 1 to R.drawable.ic_star_character, + 2 to R.drawable.ic_bear, + 3 to R.drawable.ic_raccoon, + 4 to R.drawable.ic_cat, + 5 to R.drawable.ic_rabbit, + 6 to R.drawable.ic_fox, + 7 to R.drawable.ic_water, + 8 to R.drawable.ic_penguin, + 9 to R.drawable.ic_dog, + 10 to R.drawable.ic_mouse, + 11 to R.drawable.ic_panda + ) + const val JOB_DESIGN = "๋””์ž์ธ" const val JOB_DEVELOPMENT = "๊ฐœ๋ฐœ" const val JOB_PLANNING = "๊ธฐํš" diff --git a/app/src/main/java/com/teumteum/teumteum/util/custom/view/BackCardView.kt b/app/src/main/java/com/teumteum/teumteum/util/custom/view/BackCardView.kt index 904d2dd9..fe772838 100644 --- a/app/src/main/java/com/teumteum/teumteum/util/custom/view/BackCardView.kt +++ b/app/src/main/java/com/teumteum/teumteum/util/custom/view/BackCardView.kt @@ -19,6 +19,7 @@ import com.google.android.flexbox.FlexWrap import com.google.android.flexbox.FlexboxLayoutManager import com.google.android.flexbox.JustifyContent import com.teumteum.teumteum.R +import com.teumteum.teumteum.util.ResMapper import com.teumteum.teumteum.util.callback.OnCurrentListChangedListener import com.teumteum.teumteum.util.custom.itemdecoration.FlexboxItemDecoration import com.teumteum.teumteum.util.custom.view.adapter.InterestAdapter @@ -163,7 +164,10 @@ class BackCardView : CardView, OnCurrentListChangedListener { private fun setUpViews() { tvGoalTitle.text = backCard.goalTitle tvGoalContent.text = backCard.goalContent - backCard.characterResId?.let { ivCharacter.setImageResource(it) } + backCard.characterResId?.let { + ivCharacter.setImageResource(it) + tvGoalTitle.setTextColor(ResMapper.getColorByBackCardCharacterDrawble(context, it)) + } ivFloat.setImageResource(backCard.floatResId) } diff --git a/app/src/main/res/layout/fragment_get_name.xml b/app/src/main/res/layout/fragment_get_name.xml index 314620b8..0eb0b8f3 100644 --- a/app/src/main/res/layout/fragment_get_name.xml +++ b/app/src/main/res/layout/fragment_get_name.xml @@ -79,5 +79,17 @@ app:layout_constraintTop_toBottomOf="@id/tv_name" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3947a0ae..ac95967c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,6 +57,7 @@ ํ‹ˆํ‹ˆ์€ ์‹ ๋ขฐ ๊ธฐ๋ฐ˜ ์ปค๋ฎค๋‹ˆํ‹ฐ๋กœ ์‹ค๋ช…์œผ๋กœ\n๋Œ€ํ™”ํ•˜๊ณ  ์žˆ์–ด์š” ์ด๋ฆ„ ์‹ค๋ช…์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” + ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์•„์š”. ์ƒ์ผ์ด ์–ธ์ œ์ธ๊ฐ€์š”? ๋˜๋ž˜์™€ ํ•จ๊ป˜ํ•˜๋Š” ๋งž์ถคํ˜• ๋ชจ์ž„์„ ์ถ”์ฒœํ•ด ๋“œ๋ ค์š” 2000๋…„ diff --git a/core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt b/core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt index 62055bb5..fbd9a954 100644 --- a/core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt +++ b/core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt @@ -1,9 +1,9 @@ package com.teumteum.data.datasource.remote -import com.teumteum.data.model.request.RequestReviewFriend +import com.teumteum.data.model.request.RequestReviewFriends import com.teumteum.data.model.response.ResponseGroup import com.teumteum.data.model.response.ResponseMeeting -import com.teumteum.data.model.response.ResponseReviewFriends +import com.teumteum.data.model.response.ResponseReviewFriend import com.teumteum.data.service.GroupService import okhttp3.MultipartBody import okhttp3.RequestBody @@ -85,13 +85,13 @@ class RemoteGroupDataSource @Inject constructor( suspend fun getReviewFriendList( meetingId: Long - ): ResponseReviewFriends { + ): List { return service.getReviewFriendList(meetingId) } suspend fun postRegisterReview( meetingId: Long, - requestReviewFriends: List + requestReviewFriends: RequestReviewFriends ): Boolean { return service.postRegisterReview(meetingId, requestReviewFriends).isSuccessful } diff --git a/core/data/src/main/java/com/teumteum/data/interceptor/AuthInterceptor.kt b/core/data/src/main/java/com/teumteum/data/interceptor/AuthInterceptor.kt index 7fc7e5e1..0e3d816b 100644 --- a/core/data/src/main/java/com/teumteum/data/interceptor/AuthInterceptor.kt +++ b/core/data/src/main/java/com/teumteum/data/interceptor/AuthInterceptor.kt @@ -29,7 +29,7 @@ class AuthInterceptor @Inject constructor( try { Timber.tag("๋งŒ๋ฃŒ๋œ ํ† ํฐ").d("accessToken: ${dataStore.userToken}, refreshToken: ${dataStore.refreshToken}") val refreshTokenRequest = originalRequest.newBuilder().post("".toRequestBody()) - .url("$BASE_URL/auth/reissues") + .url("${BASE_URL}auth/reissues") .addHeader(HEADER_AUTHORIZATION, dataStore.userToken) .addHeader(HEADER_REFRESH_TOKEN, dataStore.refreshToken) .build() diff --git a/core/data/src/main/java/com/teumteum/data/model/request/RequestReviewFriend.kt b/core/data/src/main/java/com/teumteum/data/model/request/RequestReviewFriend.kt index 3461be89..1f591509 100644 --- a/core/data/src/main/java/com/teumteum/data/model/request/RequestReviewFriend.kt +++ b/core/data/src/main/java/com/teumteum/data/model/request/RequestReviewFriend.kt @@ -3,6 +3,11 @@ package com.teumteum.data.model.request import com.teumteum.domain.entity.ReviewFriend import kotlinx.serialization.Serializable +@Serializable +data class RequestReviewFriends( + val reviews: List +) + @Serializable data class RequestReviewFriend( val id: Long, diff --git a/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt b/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt index bdf6d783..cfac34f9 100644 --- a/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt +++ b/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt @@ -3,9 +3,9 @@ package com.teumteum.data.repository import android.util.Log import com.google.gson.Gson import com.teumteum.data.datasource.remote.RemoteGroupDataSource +import com.teumteum.data.model.request.RequestReviewFriends import com.teumteum.data.model.request.toBody import com.teumteum.data.model.request.toRequestReviewFriend -import com.teumteum.domain.TeumTeumDataStore import com.teumteum.domain.entity.Meeting import com.teumteum.domain.entity.MoimEntity import com.teumteum.domain.entity.ReviewFriend @@ -98,7 +98,7 @@ class GroupRepositoryImpl @Inject constructor( override suspend fun getReviewFriendList(meetingId: Long): Result> { return runCatching { - dataSource.getReviewFriendList(meetingId).participants.map { it.toReviewFriend() } + dataSource.getReviewFriendList(meetingId).map { it.toReviewFriend() } } } @@ -107,7 +107,7 @@ class GroupRepositoryImpl @Inject constructor( request: List ): Result { return runCatching { - dataSource.postRegisterReview(meetingId, request.map { it.toRequestReviewFriend() }) + dataSource.postRegisterReview(meetingId, RequestReviewFriends(request.map { it.toRequestReviewFriend() })) } } override suspend fun saveBookmark(meetingId: Long): Result { diff --git a/core/data/src/main/java/com/teumteum/data/service/GroupService.kt b/core/data/src/main/java/com/teumteum/data/service/GroupService.kt index a5f91bc5..90d2bccd 100644 --- a/core/data/src/main/java/com/teumteum/data/service/GroupService.kt +++ b/core/data/src/main/java/com/teumteum/data/service/GroupService.kt @@ -1,10 +1,9 @@ package com.teumteum.data.service -import com.teumteum.data.model.request.RequestReviewFriend +import com.teumteum.data.model.request.RequestReviewFriends import com.teumteum.data.model.response.ResponseGroup import com.teumteum.data.model.response.ResponseMeeting -import com.teumteum.data.model.response.ResponseReviewFriends -import com.teumteum.domain.entity.Meeting +import com.teumteum.data.model.response.ResponseReviewFriend import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.Response @@ -85,11 +84,11 @@ interface GroupService { @GET("meetings/{meetingId}/participants") suspend fun getReviewFriendList( @Path("meetingId") meetingId: Long - ): ResponseReviewFriends + ): List @POST("users/reviews") suspend fun postRegisterReview( @Query("meetingId") meetingsId: Long, - @Body request: List + @Body request: RequestReviewFriends ):Response } \ No newline at end of file