diff --git a/.gitignore b/.gitignore index e69de29b..7a7c00c8 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,291 @@ +# Created by https://www.toptal.com/developers/gitignore/api/macos,windows,gradle,intellij+all,java,intellij,sonar +# Edit at https://www.toptal.com/developers/gitignore?templates=macos,windows,gradle,intellij+all,java,intellij,sonar + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# AWS User-specific + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# SonarLint plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### Intellij+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Sonar ### +#Sonar generated dir +/.sonar/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Gradle Patch ### +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/macos,windows,gradle,intellij+all,java,intellij,sonar \ No newline at end of file diff --git a/.idea/sonarlint/issuestore/1/2/12e74ec3d058fd5c3591dbd03535b11ce2aa099a b/.idea/sonarlint/issuestore/1/2/12e74ec3d058fd5c3591dbd03535b11ce2aa099a deleted file mode 100644 index e69de29b..00000000 diff --git a/.idea/sonarlint/issuestore/1/9/1971a7780cde29eecf35980e90fd6a543f2272ce b/.idea/sonarlint/issuestore/1/9/1971a7780cde29eecf35980e90fd6a543f2272ce deleted file mode 100644 index e69de29b..00000000 diff --git a/.idea/sonarlint/issuestore/1/a/1a222870c2bab9d606c7f94739b8a006ed8ce06f b/.idea/sonarlint/issuestore/1/a/1a222870c2bab9d606c7f94739b8a006ed8ce06f deleted file mode 100644 index e69de29b..00000000 diff --git a/.idea/sonarlint/issuestore/b/2/b29bd1f7028776d53a3de51178113ae25a5efa01 b/.idea/sonarlint/issuestore/b/2/b29bd1f7028776d53a3de51178113ae25a5efa01 deleted file mode 100644 index e69de29b..00000000 diff --git a/.idea/sonarlint/securityhotspotstore/2/3/2363d464b7abe433f93c6cab2d693ce0bd00ed52 b/.idea/sonarlint/securityhotspotstore/2/3/2363d464b7abe433f93c6cab2d693ce0bd00ed52 deleted file mode 100644 index e69de29b..00000000 diff --git a/.idea/sonarlint/securityhotspotstore/b/2/b29bd1f7028776d53a3de51178113ae25a5efa01 b/.idea/sonarlint/securityhotspotstore/b/2/b29bd1f7028776d53a3de51178113ae25a5efa01 deleted file mode 100644 index e69de29b..00000000 diff --git a/android/HowAboutTrip/.idea/appInsightsSettings.xml b/android/HowAboutTrip/.idea/appInsightsSettings.xml new file mode 100644 index 00000000..23b2e1fe --- /dev/null +++ b/android/HowAboutTrip/.idea/appInsightsSettings.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/build.gradle.kts b/android/HowAboutTrip/app/build.gradle.kts index 6205d766..b3331632 100644 --- a/android/HowAboutTrip/app/build.gradle.kts +++ b/android/HowAboutTrip/app/build.gradle.kts @@ -25,9 +25,12 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + resValue("string", "API_SERVER", getApiKey("api_server")) + buildConfigField("String", "GOOGLE_OAUTH_ID", getApiKey("google_oauth_id")) buildConfigField("String", "GOOGLE_MAP_API_KEY", getApiKey("google_map_api_key")) buildConfigField("String", "GOOGLE_SERVER_ID", getApiKey("google_server_id")) + buildConfigField("String", "API_SERVER", getApiKey("api_server")) } buildTypes { @@ -58,15 +61,24 @@ dependencies { implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("com.airbnb.android:lottie:6.3.0") - implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2") - implementation("androidx.fragment:fragment-ktx:1.7.0-alpha07") - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") + implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0") + implementation("androidx.fragment:fragment-ktx:1.7.0-alpha08") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0") + implementation("androidx.datastore:datastore-preferences:1.0.0") implementation(platform("com.google.firebase:firebase-bom:32.7.0")) implementation("com.google.firebase:firebase-analytics") - implementation("com.google.firebase:firebase-auth:22.3.0") + implementation("com.google.firebase:firebase-auth:22.3.1") implementation("com.google.android.gms:play-services-auth:20.7.0") + implementation("com.squareup.retrofit:retrofit:2.0.0-beta2") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.12") + implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") + implementation("com.squareup.retrofit2:converter-scalars:2.9.0") + + implementation("com.github.bumptech.glide:glide:5.0.0-rc01") + testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") diff --git a/android/HowAboutTrip/app/src/main/AndroidManifest.xml b/android/HowAboutTrip/app/src/main/AndroidManifest.xml index 67856c38..af2348be 100644 --- a/android/HowAboutTrip/app/src/main/AndroidManifest.xml +++ b/android/HowAboutTrip/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ - + + + android:exported="true"> + + + + android:exported="true" + android:theme="@style/Theme.HowAboutTrip.BlackStatusBar"> @@ -29,7 +37,9 @@ + android:theme="@style/Theme.HowAboutTrip.BlackStatusBar" + android:exported="true"> + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/adapter/CalendarAdapter.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/adapter/CalendarAdapter.kt new file mode 100644 index 00000000..1811f8be --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/adapter/CalendarAdapter.kt @@ -0,0 +1,154 @@ +package com.project.how.adapter + +import android.graphics.Color +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.project.how.R +import com.project.how.databinding.CalendarDayItemBinding +import java.time.LocalDate + +class CalendarAdapter( + repositoryDays : List, + selectedDate : LocalDate, + private val onItemClickListener : OnItemClickListener) + : RecyclerView.Adapter() { + private var sd = selectedDate + private var selected : MutableList = mutableListOf() + private val selectedMonthDays : MutableMap> = mutableMapOf() + private val selectedTwoDay : MutableMap = mutableMapOf() + private var days = repositoryDays + private var emptyCount = 0 + private var dayCount = 1 + private var selectedCount = 0 + + init { + Log.d("CalendarAdapter", "init repositoryDays.size : ${repositoryDays.size}\n${days.size}") + initSelected() + } + + inner class ViewHolder(val binding : CalendarDayItemBinding) : RecyclerView.ViewHolder(binding.root){ + fun bind(data: Int, position: Int){ + if(data != EMPTY){ + binding.day.text = dayCount++.toString() + val firstSelected = selectedTwoDay[FIRST] + val secondSelected = selectedTwoDay[SECOND] + if(firstSelected != null && secondSelected != null){ + if(firstSelected.month.value < secondSelected.month.value){ + if((position - emptyCount) < secondSelected.dayOfMonth){ + binding.day.setTextColor(Color.parseColor("#00000000")) + binding.background.setBackgroundResource(R.color.black) + } + }else if(firstSelected.month.value > secondSelected.month.value){ + if((position - emptyCount) < firstSelected.dayOfMonth){ + binding.day.setTextColor(Color.parseColor("#00000000")) + binding.background.setBackgroundResource(R.color.black) + } + }else{ + if(firstSelected.dayOfMonth < secondSelected.dayOfMonth){ + if((firstSelected.dayOfMonth < (position - emptyCount)) && (secondSelected.dayOfMonth > (position - emptyCount))) { + binding.day.setTextColor(Color.parseColor("#00000000")) + binding.background.setBackgroundResource(R.color.black) + } + }else if(firstSelected.dayOfMonth > secondSelected.dayOfMonth){ + if((firstSelected.dayOfMonth > (position - emptyCount)) && (secondSelected.dayOfMonth < (position - emptyCount))) { + binding.day.setTextColor(Color.parseColor("#00000000")) + binding.background.setBackgroundResource(R.color.black) + } + } + } + } + binding.day.setOnClickListener { +// selected[position] = !selected[position] + selectedTwoDay[selectedCount++%2] = sd.withDayOfMonth(position-emptyCount) + val sd = sd.withDayOfMonth(position-emptyCount) + onItemClickListener.onItemClickListener(data, selected, position, sd) + } + + changeColor(binding, position) + }else{ + binding.day.text = " " + emptyCount++ + } + + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder( + CalendarDayItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + + override fun getItemCount(): Int = days.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val data = days[position] + holder.bind(data, position) + } + + fun update(newDays : List, sd: LocalDate){ + days = newDays + dayCount = 1 + emptyCount = 0 + observeMonthChange(sd) + notifyDataSetChanged() + } + + fun observeMonthChange(sd : LocalDate){ + selectedMonthDays[this.sd.month.value] = selected + this.sd = sd + initSelected() + } + + private fun initSelected(){ + Log.d("CalendarAdapter", "Before ${selected.size}\n${days.size}") + selected = mutableListOf() + for(i in days.indices){ + selected.add(false) + } + Log.d("CalendarAdapter", "After ${selected.size}\n${days.size}") + } + + fun resetSelected(){ + for(i in days.indices) + selected[i] = false + dayCount = 1 + emptyCount = 0 + notifyDataSetChanged() + } + + private fun changeColor(binding: CalendarDayItemBinding, position: Int){ + if(selected[position]){ + binding.day.setTextColor(Color.parseColor("#FFFFFFFF")) + binding.background.setBackgroundResource(R.drawable.black_oval_day_background) + }else{ + binding.day.setTextColor(Color.parseColor("#FF000000")) + binding.background.setBackgroundResource(R.drawable.white_oval_day_background) + } + } + + fun getSelectedDays() : MutableMap?{ + if (selectedTwoDay[FIRST] != null || selectedTwoDay[SECOND] != null) + return selectedTwoDay + return null + } + + fun getSelectedDay() : LocalDate?{ + if (selectedTwoDay[FIRST] != null) + return selectedTwoDay[FIRST] + return null + } + + interface OnItemClickListener{ + fun onItemClickListener(data : Int, selected : MutableList, position: Int, sd: LocalDate){} + } + companion object{ + private const val EMPTY = 99 + private const val FIRST = 0 + private const val SECOND = 1 + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/MemberInfo.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/MemberInfo.kt new file mode 100644 index 00000000..2c2958fe --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/MemberInfo.kt @@ -0,0 +1,7 @@ +package com.project.how.data_class + +data class MemberInfo( + val name : String, + val birth : String, + val phone : String +) diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/Tokens.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/Tokens.kt new file mode 100644 index 00000000..07f922ef --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/Tokens.kt @@ -0,0 +1,6 @@ +package com.project.how.data_class + +data class Tokens( + val accessToken : String, + val refreshToken: String +) diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/AuthRecreateRequest.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/AuthRecreateRequest.kt new file mode 100644 index 00000000..0b3365f4 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/AuthRecreateRequest.kt @@ -0,0 +1,7 @@ +package com.project.how.data_class.dto + +import com.google.gson.annotations.SerializedName + +data class AuthRecreateRequest( + @SerializedName("refreshToken") val refreshToken : String +) diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/EmptyResponse.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/EmptyResponse.kt new file mode 100644 index 00000000..6be866f3 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/EmptyResponse.kt @@ -0,0 +1,3 @@ +package com.project.how.data_class.dto + +class EmptyResponse() diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/GetInfoResponse.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/GetInfoResponse.kt new file mode 100644 index 00000000..2359be4c --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/GetInfoResponse.kt @@ -0,0 +1,10 @@ +package com.project.how.data_class.dto + +import com.google.gson.annotations.SerializedName + +data class GetInfoResponse( + @SerializedName("uid") val uid : String, + @SerializedName("name") val name : String, + @SerializedName("birth") val birth : String, + @SerializedName("phoneNumber") val phone : String +) diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/LoginRequest.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/LoginRequest.kt new file mode 100644 index 00000000..d890cb60 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/LoginRequest.kt @@ -0,0 +1,6 @@ +package com.project.how.data_class.dto +import com.google.gson.annotations.SerializedName + +data class LoginRequest ( + @SerializedName("uid") val uid : String +) \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/SignUpInfo.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/SignUpInfo.kt new file mode 100644 index 00000000..3e9f7aaa --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/SignUpInfo.kt @@ -0,0 +1,7 @@ +package com.project.how.data_class.dto + +data class SignUpInfo( + val name : String, + val birth : String, + val phone : String +) diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/SignUpRequest.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/SignUpRequest.kt new file mode 100644 index 00000000..0a76791c --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/data_class/dto/SignUpRequest.kt @@ -0,0 +1,9 @@ +package com.project.how.data_class.dto + +import com.google.gson.annotations.SerializedName + +data class SignUpRequest( + @SerializedName("name") val name : String, + @SerializedName("birth") val birth : String, + @SerializedName("phoneNumber") val phone : String +) diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/datastore/TokenDataStore.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/datastore/TokenDataStore.kt new file mode 100644 index 00000000..71b74980 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/datastore/TokenDataStore.kt @@ -0,0 +1,37 @@ +package com.project.how.datastore + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import com.project.how.data_class.Tokens +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map + +object TokenDataStore { + val Context.dataStore: DataStore by preferencesDataStore(name = "tokens") + + val ACCESS_TOKEN = stringPreferencesKey("access_token") + val REFRESH_TOKEN = stringPreferencesKey("refresh_token") + + suspend fun saveTokens(context: Context, tokens : Tokens){ + context.dataStore.edit { + it[ACCESS_TOKEN] = tokens.accessToken + it[REFRESH_TOKEN] = tokens.refreshToken + } + } + fun getTokens(context: Context): Flow = flow { + context.dataStore.data.collect { + val accessToken = it[ACCESS_TOKEN] + val refreshToken = it[REFRESH_TOKEN] + if(accessToken.isNullOrEmpty() || refreshToken.isNullOrEmpty()){ + this.emit(null) + }else{ + this.emit(Tokens(accessToken, refreshToken)) + } + } + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/model/CalendarRepository.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/model/CalendarRepository.kt new file mode 100644 index 00000000..4e32fcf6 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/model/CalendarRepository.kt @@ -0,0 +1,76 @@ +package com.project.how.model + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import java.time.LocalDate + +class CalendarRepository { + private val nowDate = LocalDate.now() + private val _selectedDate = MutableLiveData() + val selectedDate : LiveData + get() = _selectedDate + private lateinit var monthOfFirstDate : LocalDate + private lateinit var sd : LocalDate + private var monthOfFirstDayOfWeek = Companion.EMPTY + private var lastDay = 0 + + private fun getMonthInform(fdw : Int) : Flow> = flow { + val monthInfo = mutableListOf() + lastDay = sd.lengthOfMonth() + var week = fdw + for (i in 0 until fdw) + monthInfo.add(Companion.EMPTY) + for(i in 1..lastDay){ + monthInfo.add(week) + week = (week+1) % 7 + } + this.emit(monthInfo) + } + + private fun getMonthOfFirstDayOfWeekChangeInt() : Int { + when(monthOfFirstDate.dayOfWeek.toString()){ + "MONDAY" -> return 1 + "TUESDAY" -> return 2 + "WEDNESDAY" -> return 3 + "THURSDAY" -> return 4 + "FRIDAY" -> return 5 + "SATURDAY" -> return 6 + "SUNDAY" -> return 0 + else -> { + Log.e("getMonthOfFirstDayOfWeek", "monthOfFirstDate.dayOfWeek.toString() go to else case\n${monthOfFirstDate.dayOfWeek}") + return 99} + } + } + + private fun getFirstDate(): Flow> { + monthOfFirstDate = sd.withDayOfMonth(1)!! + monthOfFirstDayOfWeek = getMonthOfFirstDayOfWeekChangeInt() + return getMonthInform(monthOfFirstDayOfWeek) + } + + fun plusSelectedDate(): Flow> { + sd = sd.plusMonths(1) + _selectedDate.postValue(sd) + return getFirstDate() + } + + fun minusSelectedDate(): Flow> { + sd = sd.minusMonths(1) + _selectedDate.postValue(sd) + return getFirstDate() + } + + fun init() : Flow>{ + sd = nowDate + _selectedDate.postValue(nowDate) + return getFirstDate() + } + + companion object { + private const val EMPTY = 99 + } + +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/model/LoginRepository.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/model/LoginRepository.kt deleted file mode 100644 index 40d3617f..00000000 --- a/android/HowAboutTrip/app/src/main/java/com/project/how/model/LoginRepository.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.project.how.model - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import com.google.firebase.auth.FirebaseAuth -import com.google.firebase.auth.FirebaseUser -import com.google.firebase.auth.GoogleAuthProvider - -class LoginRepository { - private val firebaseAuth = FirebaseAuth.getInstance() - private val _userLiveData = MutableLiveData() - val userLiveData: LiveData - get() = _userLiveData - - fun getUser(idToken: String) { - val credential = GoogleAuthProvider.getCredential(idToken, null) - firebaseAuth.signInWithCredential(credential).addOnCompleteListener{ - if(it.isSuccessful){ - _userLiveData.postValue(firebaseAuth.currentUser) - } else{ - Log.e("GoogleAuthRepository", "getUser is failed\n${it.exception}") - } - } - } -} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/model/MemberRepository.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/model/MemberRepository.kt new file mode 100644 index 00000000..5e6f12d9 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/model/MemberRepository.kt @@ -0,0 +1,79 @@ +package com.project.how.model + +import android.content.Context +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.FirebaseUser +import com.google.firebase.auth.GoogleAuthProvider +import com.project.how.data_class.MemberInfo +import com.project.how.data_class.Tokens +import com.project.how.datastore.TokenDataStore + +class MemberRepository { + private val firebaseAuth = FirebaseAuth.getInstance() + private val _currentUserLiveData = MutableLiveData() + private val _userLiveData = MutableLiveData() + private val _tokensLiveData = MutableLiveData() + private val _tokensSaveLiveData = MutableLiveData() + private val _Member_infoLiveData = MutableLiveData() + val currentUserLiveData : LiveData + get() = _currentUserLiveData + val userLiveData: LiveData + get() = _userLiveData + val tokensLiveData : LiveData + get() = _tokensLiveData + val tokensSaveLiveData : LiveData + get() = _tokensSaveLiveData + val memberInfoLiveData : LiveData + get() = _Member_infoLiveData + + fun getUser(idToken: String) { + val credential = GoogleAuthProvider.getCredential(idToken, null) + firebaseAuth.signInWithCredential(credential).addOnCompleteListener{ + if(it.isSuccessful){ + _userLiveData.postValue(firebaseAuth.currentUser) + } else{ + Log.e("GoogleAuthRepository", "getUser is failed\n${it.exception}") + } + } + } + + suspend fun init(context: Context) { + Log.d("init", "LoginRepository init start") + TokenDataStore.getTokens(context).collect{ + Log.d("init", "LoginRepository init getTokens() \tToken is null : ${it == null}") + if (it != null){ + Log.d("init", "LoginRepository init getTokens()\naccessToken : ${it.accessToken}\nrefreshToken : ${it.refreshToken}") + _tokensLiveData.postValue(it) + _tokensSaveLiveData.postValue(true) + }else{ + Log.d("init", "LoginRepository init getTokens() _tokensSaveLiveData.postValue(false)") + _tokensSaveLiveData.postValue(false) + } + } + Log.d("init", "LoginRepository init end") + } + + fun checkCurrentUser() { + val currentUser = firebaseAuth.currentUser + if(currentUser != null){ + Log.d("checkCurrentUser", "firebaseAuth.current != null\nemail : ${currentUser.email}\ndisplayName : ${currentUser.displayName}") + _currentUserLiveData.postValue(currentUser!!) + Log.d("checkCurrentUser", "currentUserLiveData.value : ${currentUserLiveData.value}") + }else{ + Log.d("checkCurrentUser", "firebaseAuth.current == null") + } + } + + suspend fun getTokens(context: Context, accessToken : String, refreshToken: String) { + val tokens = Tokens(accessToken, refreshToken) + _tokensLiveData.postValue(tokens) + TokenDataStore.saveTokens(context, Tokens(accessToken, refreshToken)) + } + + fun getInfo(memberInfo : MemberInfo){ + _Member_infoLiveData.postValue(memberInfo) + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/network/api_interface/MemberService.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/network/api_interface/MemberService.kt new file mode 100644 index 00000000..8d546d8e --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/network/api_interface/MemberService.kt @@ -0,0 +1,37 @@ +package com.project.how.network.api_interface + +import com.project.how.data_class.dto.EmptyResponse +import com.project.how.data_class.dto.LoginRequest +import com.project.how.data_class.dto.SignUpRequest +import com.project.how.data_class.dto.AuthRecreateRequest +import com.project.how.data_class.dto.GetInfoResponse +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.Headers +import retrofit2.http.POST +import retrofit2.http.PUT + +interface MemberService { + @POST("members/login") + fun login( + @Body login: LoginRequest + ) : Call + + @PUT("members/signup") + fun signUp( + @Header("Authorization") accessToken : String, + @Body signUp: SignUpRequest + ) : Call + + @POST("members/refresh") + fun authRecreate( + @Body authRecreate : AuthRecreateRequest + ) : Call + + @GET("members/info") + fun getInfo( + @Header("Authorization") accessToken: String + ) : Call +} diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/network/client/MemberRetrofit.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/network/client/MemberRetrofit.kt new file mode 100644 index 00000000..475f5f0e --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/network/client/MemberRetrofit.kt @@ -0,0 +1,41 @@ +package com.project.how.network.client + +import com.google.gson.GsonBuilder +import com.project.how.BuildConfig +import com.project.how.network.api_interface.MemberService +import com.project.how.network.converter_factory.NullOnEmptyConverterFactory +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.converter.scalars.ScalarsConverterFactory +import java.util.concurrent.TimeUnit + +object MemberRetrofit { + private const val BASE_URL = BuildConfig.API_SERVER + + fun getApiService() : MemberService? = getInstance()?.create(MemberService::class.java) + + private fun getInstance() : Retrofit? { + val gson = GsonBuilder().setLenient().create() + + val httpClient = OkHttpClient.Builder() + .connectTimeout(2, TimeUnit.MINUTES) + .readTimeout(1, TimeUnit.MINUTES) + .writeTimeout(1, TimeUnit.MINUTES) + + val loggingInterceptor = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + httpClient.addInterceptor(loggingInterceptor) + + return Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(ScalarsConverterFactory.create()) + .addConverterFactory(NullOnEmptyConverterFactory()) + .addConverterFactory(GsonConverterFactory.create(gson)) + .client(httpClient.build()) + .build() + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/network/converter_factory/NullOnEmptyConverterFactory.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/network/converter_factory/NullOnEmptyConverterFactory.kt new file mode 100644 index 00000000..c10c38c7 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/network/converter_factory/NullOnEmptyConverterFactory.kt @@ -0,0 +1,19 @@ +package com.project.how.network.converter_factory + + +import com.project.how.data_class.dto.EmptyResponse +import okhttp3.ResponseBody +import retrofit2.Converter +import retrofit2.Retrofit +import java.lang.reflect.Type + +class NullOnEmptyConverterFactory : Converter.Factory() { + override fun responseBodyConverter(type: Type?, annotations: Array?, retrofit: Retrofit?): Converter? { + val delegate = retrofit!!.nextResponseBodyConverter(this, type!!, annotations!!) + return Converter { + if (it.contentLength() == 0L) return@Converter EmptyResponse() + delegate.convert(it) + } + } + +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/LoginActivity.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/LoginActivity.kt index 354a3599..27587970 100644 --- a/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/LoginActivity.kt +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/LoginActivity.kt @@ -6,32 +6,35 @@ import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import android.widget.Toast -import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.databinding.DataBindingUtil -import com.google.android.gms.auth.api.identity.BeginSignInRequest +import androidx.lifecycle.lifecycleScope import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInClient import com.google.android.gms.auth.api.signin.GoogleSignInOptions -import com.google.android.gms.common.api.ApiException import com.project.how.BuildConfig import com.project.how.R +import com.project.how.data_class.dto.LoginRequest import com.project.how.databinding.ActivityLoginBinding -import com.project.how.view_model.LoginViewModel +import com.project.how.view_model.MemberViewModel +import kotlinx.coroutines.launch class LoginActivity : AppCompatActivity() { private lateinit var binding : ActivityLoginBinding - private val viewModel: LoginViewModel by viewModels() + private val viewModel: MemberViewModel by viewModels() private lateinit var activityResultLauncher : ActivityResultLauncher private lateinit var googleSignInRequest: GoogleSignInClient + private lateinit var gso : GoogleSignInOptions override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_login) binding.login = this - val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + binding.lifecycleOwner = this + + gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(BuildConfig.GOOGLE_SERVER_ID) .requestEmail() .build() @@ -42,17 +45,85 @@ class LoginActivity : AppCompatActivity() { try { val account = task.result viewModel.getUser(account.idToken!!) - Log.d("activityResultLauncher", "Login Success\nidToken : ${account.idToken}\nid : ${account.id}\nemail : ${account.email}") - startActivity(Intent(this, MainActivity::class.java)) + viewModel.userLiveData.observe(this){user-> + Log.d("activityResultLauncher", "Login Success\nidToken : ${account.idToken}\nid : ${account.id}\nemail : ${account.email}\nuid : ${user.uid}") + sendUid(user.uid) + } } catch (e: Exception){ Log.e("activityResultLauncher", "Login Failed\nError : ${e.stackTrace}\n${e.message}") } } } + } + + override fun onStart() { + super.onStart() + viewModel.currentUserLiveData.observe(this) { user -> + if (user != null) { + Log.d("onStart", "viewModel.currentUserLiveData.value != null") + autoLogin() + } else { + Log.d("onStart", "viewModel.currentUserLiveData.value == null") + } + } + } + + private fun sendUid(uid : String){ + lifecycleScope.launch { + val loginRequest = LoginRequest(uid) + val code = viewModel.getTokens(this@LoginActivity, loginRequest) + if(code == EXISTING_MEMBER){ + Log.d("sendUid", "Existing member") + moveMain() + }else if(code == NEW_MEMBER){ + Log.d("sendUid", "New member") + moveSignUp() + }else{ + Log.e("sendUid", "Login failed") + Toast.makeText(this@LoginActivity, "[로그인 실패] HowAboutTrip 로그인에 실패했습니다.\n해당 오류가 지속될 경우 문의하시기를 바랍니다.", Toast.LENGTH_SHORT).show() + } + } + } + + private fun autoLogin() { + googleSignInRequest.silentSignIn().addOnCompleteListener(this) { task -> + if (task.isSuccessful){ + try { + val account = task.result + viewModel.getUser(account.idToken!!) + viewModel.userLiveData.observe(this){user-> + Log.d("autoLogin", "Auto Login Success\nidToken : ${account.idToken}\nid : ${account.id}\nemail : ${account.email}\nuid : ${user.uid}") + sendUid(user.uid) + } + } catch (e: Exception) { + Log.e("autoLogin", "Auto Login Failed\nError : ${e.stackTrace}\n${e.message}") + } + } else{ + Log.e("autoLogin", "Auto Login Failed\nError : ${task.exception}") + } + } + } + fun login(){ + activityResultLauncher.launch(googleSignInRequest.signInIntent) + binding.lottie.pauseAnimation() + } + + private fun moveSignUp(){ + viewModel.tokensLiveData.observe(this){ + startActivity(Intent(this, SignUpActivity::class.java)) + finish() + } + } - binding.googleLogin.setOnClickListener { - activityResultLauncher.launch(googleSignInRequest.signInIntent) - binding.lottie.pauseAnimation() + private fun moveMain(){ + viewModel.tokensLiveData.observe(this){ + startActivity(Intent(this, MainActivity::class.java)) + finish() } } + + companion object{ + const val EXISTING_MEMBER = 200 + const val NEW_MEMBER = 201 + } } \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/MainActivity.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/MainActivity.kt index ad1649f3..c2664fbc 100644 --- a/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/MainActivity.kt +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/MainActivity.kt @@ -5,12 +5,42 @@ import android.os.Bundle import androidx.databinding.DataBindingUtil import com.project.how.R import com.project.how.databinding.ActivityMainBinding +import com.project.how.view.fragment.CalendarFragment +import com.project.how.view.fragment.MypageFragment +import com.project.how.view.fragment.PictureFragment +import com.project.how.view.fragment.TicketFragment class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding= DataBindingUtil.setContentView(this, R.layout.activity_main) + binding.main = this + binding.lifecycleOwner = this + supportFragmentManager.beginTransaction().add(R.id.fragment, CalendarFragment()).commitAllowingStateLoss() + binding.menu.menu.getItem(2).isEnabled = false + binding.menu.selectedItemId = R.id.menu_calendar + binding.menu.setOnItemSelectedListener { + when(it.itemId){ + R.id.menu_ticket->{ + supportFragmentManager.beginTransaction().replace(R.id.fragment, TicketFragment()) + .commitAllowingStateLoss() + } + R.id.menu_calendar->{ + supportFragmentManager.beginTransaction().replace(R.id.fragment, CalendarFragment()) + .commitAllowingStateLoss() + } + R.id.menu_picture->{ + supportFragmentManager.beginTransaction().replace(R.id.fragment, PictureFragment()) + .commitAllowingStateLoss() + } + R.id.menu_mypage->{ + supportFragmentManager.beginTransaction().replace(R.id.fragment, MypageFragment()) + .commitAllowingStateLoss() + } + } + true + } } } \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/SignUpActivity.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/SignUpActivity.kt new file mode 100644 index 00000000..d296d9d0 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/SignUpActivity.kt @@ -0,0 +1,157 @@ +package com.project.how.view.activity + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.telephony.PhoneNumberFormattingTextWatcher +import android.util.Log +import android.widget.Toast +import androidx.activity.viewModels +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.project.how.R +import com.project.how.adapter.CalendarAdapter +import com.project.how.data_class.dto.AuthRecreateRequest +import com.project.how.databinding.ActivitySignUpBinding +import com.project.how.databinding.CalendarBottomSheetBinding +import com.project.how.view_model.CalendarViewModel +import com.project.how.view_model.MemberViewModel +import kotlinx.coroutines.launch +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +class SignUpActivity : AppCompatActivity(), CalendarAdapter.OnItemClickListener { + private lateinit var binding : ActivitySignUpBinding + private lateinit var calendarBinding : CalendarBottomSheetBinding + private val calenderViewModel : CalendarViewModel by viewModels() + private val memberViewModel : MemberViewModel by viewModels() + private lateinit var days : List + private lateinit var adapter : CalendarAdapter + private var selectedDay : LocalDate? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView(this, R.layout.activity_sign_up) + calendarBinding = CalendarBottomSheetBinding.inflate(layoutInflater) + binding.signUp = this + binding.lifecycleOwner = this + + lifecycleScope.launch { + memberViewModel.init(this@SignUpActivity) + } + + binding.phone.addTextChangedListener(PhoneNumberFormattingTextWatcher()) + } + + fun sendInfo(){ + val name = binding.name.text.toString() + val phone = binding.phone.text.toString() + val birth = binding.birth.text.toString() + + Log.d("sendInfo", "IF Before\nname : $name\t${name.length}\nphone : $phone\t${phone.length}\nbirth : $birth\t${birth.length}") + + if(name.isNotEmpty() && phone.length == 13 && birth.length == 8){ + val n = name.trim() + val p = phone + val bDate = LocalDate.parse(birth, DateTimeFormatter.ofPattern("yyyyMMdd")) + val b = bDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + Log.d("sendInfo", "IF After\nname : $n\t${n.length}\nphone : $p\t${p.length}\nbirth : $b\t${b .length}") + memberViewModel.tokensLiveData.value?.let { memberViewModel.getInfoSignUp(this, it.accessToken, n, p, b) } + memberViewModel.memberInfoLiveData.observe(this){ info -> + moveMainActivity() + } + }else{ + Toast.makeText(this, "[필수] 모든 항목은 필수로 입력하셔야 합니다.\n모든 항목이 정해진 형식에 맞춰서 작성되었는지 확인하세요.", Toast.LENGTH_SHORT).show() + } + } + + private fun moveMainActivity() { + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + finish() + } + +// test용 코드 +// fun authRecreate(){ +// memberViewModel.tokensLiveData.value?.let { +// memberViewModel.authRecreate(this, AuthRecreateRequest(it.refreshToken)) +// } +// } + +// 캘린더 테스트용 코드 +// fun setCalenderBottomSheetView() { +// initializeCalendarBottomSheet() +// observeCalendarData() +// } +// +// private fun initializeCalendarBottomSheet() { +// calendarBinding = CalendarBottomSheetBinding.inflate(layoutInflater) +// val bottomSheetDialog = BottomSheetDialog(this) +// bottomSheetDialog.setContentView(calendarBinding.root) +// bottomSheetDialog.show() +// +// +// calenderViewModel.selectedDate.observe(this@SignUpActivity) { sd -> +// Log.d("selectedData observe", "initializeCalendarBottom() 시작") +// days = listOf() +// adapter = CalendarAdapter(days, sd, this) +// calendarBinding.days.layoutManager = GridLayoutManager(this, 7) +// calendarBinding.days.adapter = adapter +// } +// +// calendarBinding.left.setOnClickListener{ minusMonth() } +// calendarBinding.right.setOnClickListener { plusMonth() } +// calendarBinding.reset.setOnClickListener { resetDay() } +// calendarBinding.confirm.setOnClickListener { } +// } +// +// private fun observeCalendarData() { +// lifecycleScope.launch { +// calenderViewModel.init().collect { updatedDays -> +// calenderViewModel.selectedDate.observe(this@SignUpActivity) { sd -> +// Log.d("selectedData observe", "observeCalendarData() 시작") +// adapter.update(updatedDays, sd) +// calendarBinding.month.text = sd.month.value.toString() +// calendarBinding.year.text = sd.year.toString() +// } +// } +// } +// } +// +// private fun minusMonth(){ +// lifecycleScope.launch { +// calenderViewModel.minusSelectedDate().collect { updatedDays -> +// calenderViewModel.selectedDate.observe(this@SignUpActivity) { sd -> +// Log.d("selectedData observe", "left.setOnClickListener() 시작") +// adapter.update(updatedDays, sd) +// } +// } +// } +// } +// +// +// private fun resetDay() { +// selectedDay = null +// adapter.resetSelected() +// } +// +// private fun plusMonth(){ +// lifecycleScope.launch { +// calenderViewModel.plusSelectedDate().collect { updatedDays -> +// calenderViewModel.selectedDate.observe(this@SignUpActivity) { sd -> +// Log.d("selectedData observe", "right.setOnClickListener() 시작") +// adapter.update(updatedDays, sd) +// } +// } +// } +// } +// +// override fun onItemClickListener(data: Int, selected: MutableList, position: Int, sd : LocalDate) { +// adapter.resetSelected() +// selected[position] = !selected[position] +// selectedDay = sd +// } + +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/SplashActivity.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/SplashActivity.kt index 91971ab6..fda55d68 100644 --- a/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/SplashActivity.kt +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/activity/SplashActivity.kt @@ -3,23 +3,55 @@ package com.project.how.view.activity import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.util.Log +import androidx.activity.viewModels import androidx.databinding.DataBindingUtil import androidx.lifecycle.lifecycleScope import com.project.how.R import com.project.how.databinding.ActivitySplashBinding +import com.project.how.view_model.MemberViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch class SplashActivity : AppCompatActivity() { private lateinit var binding : ActivitySplashBinding + private val memberViewModel: MemberViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_splash) binding.splash = this lifecycleScope.launch { - delay(1000) - startActivity(Intent(this@SplashActivity, LoginActivity::class.java)) + memberViewModel.init(this@SplashActivity) } + + memberViewModel.tokensSaveLiveData.observe(this@SplashActivity){saveCheck-> + Log.d("tokensSaveLiveData observe", "start\nsaveCheck : $saveCheck") + if (saveCheck){ + getMemberInfo() + memberViewModel.memberInfoLiveData.observe(this){ + Log.d("tokenSaveLiveData observe", "memberInfoLiveData\nname : ${it.name}\nphone : ${it.phone}\nbirth : ${it.birth}") + moveMain() + } + }else{ + moveLogin() + } + } + } + + private fun getMemberInfo() { + memberViewModel.tokensLiveData.value?.let { memberViewModel.getInfo(this, it.accessToken) } + } + + private fun moveLogin(){ + val intent = Intent(this@SplashActivity, LoginActivity::class.java) + startActivity(intent) + finish() + } + + private fun moveMain(){ + val intent = Intent(this@SplashActivity, MainActivity::class.java) + startActivity(intent) + finish() } } \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/CalendarFragment.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/CalendarFragment.kt new file mode 100644 index 00000000..b0182f6c --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/CalendarFragment.kt @@ -0,0 +1,35 @@ +package com.project.how.view.fragment + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.project.how.R +import com.project.how.databinding.FragmentCalendarBinding + +class CalendarFragment : Fragment() { + private var _binding : FragmentCalendarBinding? = null + private val binding : FragmentCalendarBinding + get() = _binding!! + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = DataBindingUtil.inflate(inflater, R.layout.fragment_calendar, container, false) + binding.calendar = this + binding.lifecycleOwner = this + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/MypageFragment.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/MypageFragment.kt new file mode 100644 index 00000000..094eb9f4 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/MypageFragment.kt @@ -0,0 +1,36 @@ +package com.project.how.view.fragment + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.project.how.R +import com.project.how.databinding.FragmentMypageBinding + +class MypageFragment : Fragment() { + private var _binding : FragmentMypageBinding? = null + private val binding : FragmentMypageBinding + get() = _binding!! + var name = "닉네임 예시" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = DataBindingUtil.inflate(inflater, R.layout.fragment_mypage, container, false) + binding.mypage = this + binding.lifecycleOwner = this + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/PictureFragment.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/PictureFragment.kt new file mode 100644 index 00000000..f240796f --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/PictureFragment.kt @@ -0,0 +1,35 @@ +package com.project.how.view.fragment + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.project.how.R +import com.project.how.databinding.FragmentPictureBinding + +class PictureFragment : Fragment() { + private var _binding : FragmentPictureBinding? = null + private val binding : FragmentPictureBinding + get() = _binding!! + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = DataBindingUtil.inflate(inflater, R.layout.fragment_picture, container, false) + binding.picture = this + binding.lifecycleOwner = this + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/TicketFragment.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/TicketFragment.kt new file mode 100644 index 00000000..a7d23145 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view/fragment/TicketFragment.kt @@ -0,0 +1,35 @@ +package com.project.how.view.fragment + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.project.how.R +import com.project.how.databinding.FragmentTicketBinding + +class TicketFragment : Fragment() { + private var _binding : FragmentTicketBinding? = null + private val binding : FragmentTicketBinding + get() = _binding!! + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = DataBindingUtil.inflate(inflater, R.layout.fragment_ticket, container, false) + binding.ticket = this + binding.lifecycleOwner = this + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/CalendarViewModel.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/CalendarViewModel.kt new file mode 100644 index 00000000..fd367f46 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/CalendarViewModel.kt @@ -0,0 +1,20 @@ +package com.project.how.view_model + +import androidx.lifecycle.LiveData +import androidx.lifecycle.ViewModel +import com.project.how.model.CalendarRepository +import kotlinx.coroutines.flow.Flow +import java.time.LocalDate + +class CalendarViewModel : ViewModel() { + private var calendarRepository : CalendarRepository = CalendarRepository() + private val _selectedDate = calendarRepository.selectedDate + val selectedDate : LiveData + get() = _selectedDate + + fun init() : Flow> = calendarRepository.init() + + fun plusSelectedDate() : Flow> = calendarRepository.plusSelectedDate() + + fun minusSelectedDate() : Flow> = calendarRepository.minusSelectedDate() +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/LoginViewModel.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/LoginViewModel.kt deleted file mode 100644 index c18e0a5e..00000000 --- a/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/LoginViewModel.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.project.how.view_model - -import androidx.lifecycle.LiveData -import androidx.lifecycle.ViewModel -import com.google.firebase.auth.FirebaseUser -import com.project.how.model.LoginRepository - -class LoginViewModel : ViewModel() { - private var loginRepository : LoginRepository = LoginRepository() - private val _userLiveData = loginRepository.userLiveData - val userLiveData: LiveData - get() = _userLiveData - - fun getUser(idToken: String){ - loginRepository.getUser(idToken) - } -} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/MemberViewModel.kt b/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/MemberViewModel.kt new file mode 100644 index 00000000..aea4a5aa --- /dev/null +++ b/android/HowAboutTrip/app/src/main/java/com/project/how/view_model/MemberViewModel.kt @@ -0,0 +1,190 @@ +package com.project.how.view_model + +import android.content.Context +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.google.firebase.auth.FirebaseUser +import com.project.how.R +import com.project.how.data_class.MemberInfo +import com.project.how.data_class.dto.LoginRequest +import com.project.how.data_class.Tokens +import com.project.how.data_class.dto.AuthRecreateRequest +import com.project.how.data_class.dto.EmptyResponse +import com.project.how.data_class.dto.GetInfoResponse +import com.project.how.data_class.dto.SignUpRequest +import com.project.how.model.MemberRepository +import com.project.how.network.client.MemberRetrofit +import kotlinx.coroutines.launch +import retrofit2.Call +import retrofit2.Callback +import retrofit2.HttpException +import retrofit2.Response +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +class MemberViewModel : ViewModel() { + private var memberRepository : MemberRepository = MemberRepository() + private val _currentUserLiveData = memberRepository.currentUserLiveData + private val _userLiveData = memberRepository.userLiveData + private val _tokensLiveData = memberRepository.tokensLiveData + private val _tokensSaveLiveData = memberRepository.tokensSaveLiveData + private val _infoLiveData = memberRepository.memberInfoLiveData + val currentUserLiveData : LiveData + get() = _currentUserLiveData + val userLiveData: LiveData + get() = _userLiveData + val tokensLiveData : LiveData + get() = _tokensLiveData + val tokensSaveLiveData : LiveData + get() = _tokensSaveLiveData + val memberInfoLiveData : LiveData + get() = _infoLiveData + + private var authRecreateCount = 0 + + init { + Log.d("LoginViewModel init", "checkCurrentUser start") + memberRepository.checkCurrentUser() + Log.d("LoginViewModel init", "checkCurrentUser end") + authRecreateCount = 0 + } + + fun getUser(idToken: String) { + memberRepository.getUser(idToken) + } + + suspend fun init(context: Context){ + Log.d("init", "LoginViewModel init start") + memberRepository.init(context) + } + + fun authRecreate(context: Context, arr: AuthRecreateRequest) { + MemberRetrofit.getApiService()!! + .authRecreate(arr) + .enqueue(object : Callback{ + override fun onResponse( + call: Call, + response: Response + ) { + viewModelScope.launch { + val result = response.body().toString() + val accessToken = response.headers()[ACCESS_TOKEN] + val refreshToken = response.headers()[REFRESH_TOKEN] + Log.d( + "authRecreate success", + "code : ${response.code()}\nresult : ${result}\naccessToken : ${accessToken}\nrefreshToken : $refreshToken" + ) + memberRepository.getTokens(context, accessToken!!, refreshToken!!) + } + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("authRecreate onFailure", "${t.message}") + } + + }) + } + + suspend fun getTokens(context : Context, lr: LoginRequest) : Int = suspendCoroutine{ continuation -> + Log.d("getTokens", "loginRequest : ${lr.uid}") + MemberRetrofit.getApiService()!! + .login(lr) + .enqueue(object : Callback{ + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + viewModelScope.launch { + val result = response.body().toString() + val accessToken = response.headers()[ACCESS_TOKEN] + val refreshToken = response.headers()[REFRESH_TOKEN] + Log.d("getTokens success", "code : ${response.code()}\nresult : ${result}\naccessToken : ${accessToken}\nrefreshToken : $refreshToken") + memberRepository.getTokens(context, accessToken!!, refreshToken!!) + continuation.resume(response.code()) + } + } else { + Log.d("getTokens response is not success", "code : ${response.code()}\nError : ${response.code()}") + continuation.resumeWithException(HttpException(response)) + } + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("getTokens onFailure", "${t.message}") + continuation.resume(ON_FAILURE) + } + }) + } + + fun getInfoSignUp(context : Context, accessToken : String, name : String, birth : String, phone : String){ + val si = SignUpRequest(name, birth, phone) + MemberRetrofit.getApiService()!! + .signUp(context.getString(R.string.bearer_token, accessToken), si) + .enqueue(object : Callback{ + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful){ + memberRepository.getInfo(MemberInfo(name, birth, phone)) + Log.d("getInfoSignUp success", "code : ${response.code()}") + }else{ + Log.d("getInfoSignUp response is not success", "code : ${response.code()}") + } + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("getInfoSignUp onFailure", "${t.message}") + } + }) + } + + fun getInfo(context: Context, accessToken: String){ + MemberRetrofit.getApiService()!! + .getInfo(context.resources.getString(R.string.bearer_token, accessToken)) + .enqueue(object : Callback{ + override fun onResponse( + call: Call, + response: Response + ) { + if(response.isSuccessful){ + val result = response.body() + if(result != null){ + val name = result.name + val birth = result.birth + val phone = result.phone + memberRepository.getInfo(MemberInfo(name, birth, phone)) + Log.d("getInfo success", "code : ${response.code()}\nname : ${name}\nbirth : ${birth}\nphone : $phone") + }else{ + Log.d("getInfo result is null", "code : ${response.code()}\n message : ${response.message()}") + } + }else if(response.code() == BAD_REQUEST){ + if (authRecreateCount<2){ + tokensLiveData.value + ?.let { AuthRecreateRequest(it.refreshToken) } + ?.let { refreshToken-> + authRecreate(context, refreshToken) + authRecreateCount++} + Log.d("getInfo Bad Request", "code : ${response.code()}\nExecute authRecreate $authRecreateCount") + } + }else{ + Log.d("getInfo response is not success", "code : ${response.code()}") + } + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("getInfo onFailure", "${t.message}") + } + }) + } + + companion object{ + private const val ON_FAILURE = 99999 + private const val ACCESS_TOKEN = "Access-Token" + private const val REFRESH_TOKEN = "Refresh-Token" + private const val BAD_REQUEST = 400 + } +} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/arrow_left.png b/android/HowAboutTrip/app/src/main/res/drawable/arrow_left.png new file mode 100644 index 00000000..ee9a8bb1 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/arrow_left.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/arrow_right.png b/android/HowAboutTrip/app/src/main/res/drawable/arrow_right.png new file mode 100644 index 00000000..e5c71245 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/arrow_right.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/black_oval_day_background.xml b/android/HowAboutTrip/app/src/main/res/drawable/black_oval_day_background.xml new file mode 100644 index 00000000..01daec93 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/black_oval_day_background.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/black_oval_fab.xml b/android/HowAboutTrip/app/src/main/res/drawable/black_oval_fab.xml new file mode 100644 index 00000000..9408d3c4 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/black_oval_fab.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/black_round_rectangle.xml b/android/HowAboutTrip/app/src/main/res/drawable/black_round_rectangle.xml new file mode 100644 index 00000000..06d4a793 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/black_round_rectangle.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/gray_round_rectangle.xml b/android/HowAboutTrip/app/src/main/res/drawable/gray_round_rectangle.xml new file mode 100644 index 00000000..76ef59ea --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/gray_round_rectangle.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_ai_calendar.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_ai_calendar.png new file mode 100644 index 00000000..5163f51c Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_ai_calendar.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_ai_calendar_size_fixed.xml b/android/HowAboutTrip/app/src/main/res/drawable/icon_ai_calendar_size_fixed.xml new file mode 100644 index 00000000..bb7c30e1 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/icon_ai_calendar_size_fixed.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_alarm_new.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_alarm_new.png new file mode 100644 index 00000000..a774821c Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_alarm_new.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_alarm_none.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_alarm_none.png new file mode 100644 index 00000000..805347d6 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_alarm_none.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar.xml b/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar.xml new file mode 100644 index 00000000..52667557 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar_bold.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar_bold.png new file mode 100644 index 00000000..127f5634 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar_bold.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar_linear.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar_linear.png new file mode 100644 index 00000000..d4ef6fdb Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_calendar_linear.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage.xml b/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage.xml new file mode 100644 index 00000000..e875b68d --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage_bold.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage_bold.png new file mode 100644 index 00000000..942837af Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage_bold.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage_linear.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage_linear.png new file mode 100644 index 00000000..d8523603 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_mypage_linear.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_picture.xml b/android/HowAboutTrip/app/src/main/res/drawable/icon_picture.xml new file mode 100644 index 00000000..3f9c43d6 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/icon_picture.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_picture_bold.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_picture_bold.png new file mode 100644 index 00000000..190b3164 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_picture_bold.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_picture_linear.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_picture_linear.png new file mode 100644 index 00000000..92a3b7c7 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_picture_linear.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket.xml b/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket.xml new file mode 100644 index 00000000..80be4f3a --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket_bold.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket_bold.png new file mode 100644 index 00000000..1e28c77d Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket_bold.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket_linear.png b/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket_linear.png new file mode 100644 index 00000000..b105e752 Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/drawable/icon_ticket_linear.png differ diff --git a/android/HowAboutTrip/app/src/main/res/drawable/white_oval_day_background.xml b/android/HowAboutTrip/app/src/main/res/drawable/white_oval_day_background.xml new file mode 100644 index 00000000..26913ec2 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/white_oval_day_background.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/white_rectangle_top_shadow.xml b/android/HowAboutTrip/app/src/main/res/drawable/white_rectangle_top_shadow.xml new file mode 100644 index 00000000..eef7a6a7 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/white_rectangle_top_shadow.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/drawable/white_round_bottom_sheet_backgroud.xml b/android/HowAboutTrip/app/src/main/res/drawable/white_round_bottom_sheet_backgroud.xml new file mode 100644 index 00000000..bb7f3008 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/drawable/white_round_bottom_sheet_backgroud.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/font/noto_sans_kr_bold.ttf b/android/HowAboutTrip/app/src/main/res/font/noto_sans_kr_bold.ttf new file mode 100644 index 00000000..6cf639eb Binary files /dev/null and b/android/HowAboutTrip/app/src/main/res/font/noto_sans_kr_bold.ttf differ diff --git a/android/HowAboutTrip/app/src/main/res/layout/activity_login.xml b/android/HowAboutTrip/app/src/main/res/layout/activity_login.xml index 835729db..038709f2 100644 --- a/android/HowAboutTrip/app/src/main/res/layout/activity_login.xml +++ b/android/HowAboutTrip/app/src/main/res/layout/activity_login.xml @@ -34,6 +34,7 @@ android:fontFamily="@font/bm_hanna" android:gravity="center" android:text="@string/login_under_text" + android:textColor="@color/black" android:textSize="16sp" android:layout_marginTop="10dp" app:layout_constraintEnd_toEndOf="parent" @@ -47,6 +48,7 @@ android:background="@android:color/transparent" android:scaleType="fitCenter" android:src="@drawable/google_login" + android:onClick="@{() -> login.login()}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" diff --git a/android/HowAboutTrip/app/src/main/res/layout/activity_main.xml b/android/HowAboutTrip/app/src/main/res/layout/activity_main.xml index 2832d141..cc7b6ff2 100644 --- a/android/HowAboutTrip/app/src/main/res/layout/activity_main.xml +++ b/android/HowAboutTrip/app/src/main/res/layout/activity_main.xml @@ -8,33 +8,105 @@ name="main" type="com.project.how.view.activity.MainActivity" /> - - - + + + + + + + + + + + - + + - + android:layout_height="wrap_content" + style="@style/Widget.MaterialComponents.BottomAppBar" + android:background="@drawable/white_rectangle_top_shadow" + android:backgroundTint="@color/white" + android:layout_marginTop="30dp" + android:paddingTop="10dp" + app:fabAnchorMode="cradle" + app:fabCradleMargin="-20dp" + app:fabAlignmentMode="center"> + + + + + + + - + + - + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.9" /> - + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/layout/activity_sign_up.xml b/android/HowAboutTrip/app/src/main/res/layout/activity_sign_up.xml new file mode 100644 index 00000000..68eea381 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/layout/activity_sign_up.xml @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/layout/calendar_bottom_sheet.xml b/android/HowAboutTrip/app/src/main/res/layout/calendar_bottom_sheet.xml new file mode 100644 index 00000000..c21aebda --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/layout/calendar_bottom_sheet.xml @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/layout/calendar_day_item.xml b/android/HowAboutTrip/app/src/main/res/layout/calendar_day_item.xml new file mode 100644 index 00000000..aa09fa0e --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/layout/calendar_day_item.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/layout/fragment_calendar.xml b/android/HowAboutTrip/app/src/main/res/layout/fragment_calendar.xml new file mode 100644 index 00000000..615abe6f --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/layout/fragment_calendar.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/layout/fragment_mypage.xml b/android/HowAboutTrip/app/src/main/res/layout/fragment_mypage.xml new file mode 100644 index 00000000..07702150 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/layout/fragment_mypage.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/layout/fragment_picture.xml b/android/HowAboutTrip/app/src/main/res/layout/fragment_picture.xml new file mode 100644 index 00000000..2fc16171 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/layout/fragment_picture.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/layout/fragment_ticket.xml b/android/HowAboutTrip/app/src/main/res/layout/fragment_ticket.xml new file mode 100644 index 00000000..d40a6e23 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/layout/fragment_ticket.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/menu/main_bottom_navigation_menu.xml b/android/HowAboutTrip/app/src/main/res/menu/main_bottom_navigation_menu.xml new file mode 100644 index 00000000..4148ef88 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/menu/main_bottom_navigation_menu.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/raw/sign_up_animation.json b/android/HowAboutTrip/app/src/main/res/raw/sign_up_animation.json new file mode 100644 index 00000000..f86e393f --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/raw/sign_up_animation.json @@ -0,0 +1 @@ +{"v":"5.7.12","fr":30,"ip":0,"op":90,"w":252,"h":252,"nm":"main","ddd":0,"assets":[],"fonts":{"list":[{"fName":"Montserrat-Bold","fFamily":"Montserrat","fStyle":"Bold","ascent":74.1989135742188}]},"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":30,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":75,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":130,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":140,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":145,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[100]},{"t":160,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[126,126,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.63],[2.566,0],[0,2.63],[-2.566,0]],"o":[[0,2.63],[-2.566,0],[0,-2.63],[2.566,0]],"v":[[-44.259,-59.35],[-48.904,-54.589],[-53.55,-59.35],[-48.904,-64.111]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.890196084976,0.945098042488,0.984313726425,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":30,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":75,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":110,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":130,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":140,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":145,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[0]},{"t":160,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[126,126,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.63],[2.566,0],[0,2.63],[-2.566,0]],"o":[[0,2.63],[-2.566,0],[0,-2.63],[2.566,0]],"v":[[-56.928,-59.35],[-61.573,-54.589],[-66.219,-59.35],[-61.573,-64.111]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.890196084976,0.945098042488,0.984313726425,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Layer 1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":30,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":75,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":100,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":130,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":140,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":145,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[100]},{"t":160,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[126,126,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.63],[2.566,0],[0,2.63],[-2.566,0]],"o":[[0,2.63],[-2.566,0],[0,-2.63],[2.566,0]],"v":[[-69.597,-59.35],[-74.242,-54.589],[-78.888,-59.35],[-74.242,-64.111]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.890196084976,0.945098042488,0.984313726425,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[126,126,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-3.088],[3.088,0],[0,3.088],[-3.088,0]],"o":[[0,3.088],[-3.088,0],[0,-3.088],[3.088,0]],"v":[[-87.118,-9.954],[-92.71,-4.362],[-98.302,-9.954],[-92.71,-15.546]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[137.345,174.696,0],"to":[-9.333,-7.333,0],"ti":[9.333,7.333,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":15,"s":[81.345,130.696,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[81.345,130.696,0],"to":[11.833,6.5,0],"ti":[-11.833,-6.5,0]},{"t":27,"s":[152.345,169.696,0]}],"ix":2,"l":2},"a":{"a":0,"k":[10.345,17.696,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":15,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":18,"s":[110,110,100]},{"t":21,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.233,-1.568],[0,0],[-2.153,3.171],[0,0],[0,0],[-2.174,1.654],[0,0]],"o":[[-1.059,0.884],[0,0],[0.564,3.792],[0,0],[0,0],[1.507,2.278],[0,0],[0,0]],"v":[[11.869,18.693],[10.393,22.526],[16.754,65.315],[24.398,67.06],[30.261,58.425],[46.769,83.381],[53.569,84.534],[59.311,80.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.240553642722,0.28746511422,0.309803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.794,2.059],[0,0],[0,0],[3.504,1.555],[0,0],[1.158,-0.966],[0,0]],"o":[[2.174,-1.654],[0,0],[0,0],[3.631,-1.23],[0,0],[-1.584,-0.703],[0,0],[0,0]],"v":[[64.511,76.208],[65.213,69.348],[45.563,46.783],[55.448,43.434],[55.805,35.602],[16.262,18.06],[11.869,18.693],[59.311,80.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.270588235294,0.352941176471,0.392156892664,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":5,"nm":"|||||||||||||","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[77.157,143.452,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"t":{"d":{"k":[{"s":{"s":26.6488609313965,"f":"Montserrat-Bold","t":"|","ca":0,"j":0,"tr":0,"lh":31.9786331176758,"ls":0,"fc":[0.071,0.2,0.294]},"t":0}]},"p":{},"m":{"g":1,"a":{"a":0,"k":[0,0],"ix":2}},"a":[{"nm":"Animator 1","s":{"t":0,"xe":{"a":0,"k":0,"ix":7},"ne":{"a":0,"k":0,"ix":8},"a":{"a":0,"k":100,"ix":4},"b":1,"rn":0,"sh":1,"s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":17,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[100]},{"t":23,"s":[0]}],"ix":1},"r":1},"a":{"o":{"a":0,"k":0,"ix":9}}}]},"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":5,"nm":"ABCD36","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[77.157,143.452,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"t":{"d":{"k":[{"s":{"s":26.6488609313965,"f":"Montserrat-Bold","t":"FB5D01","ca":0,"j":0,"tr":0,"lh":31.9786331176758,"ls":0,"fc":[0.071,0.2,0.294]},"t":0}]},"p":{},"m":{"g":1,"a":{"a":0,"k":[0,0],"ix":2}},"a":[{"nm":"Animator 1","s":{"t":0,"xe":{"a":0,"k":0,"ix":7},"ne":{"a":0,"k":0,"ix":8},"a":{"a":0,"k":100,"ix":4},"b":1,"rn":0,"sh":1,"s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":23,"s":[0]},{"t":68,"s":[100]}],"ix":1},"r":1},"a":{"o":{"a":0,"k":0,"ix":9}}}]},"ip":23,"op":173,"st":23,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Layer 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[126,126,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.096,11.694],[1.436,3.137],[6.626,7.822],[34.572,0],[0,-62.394],[-62.394,0],[-20.723,24.463],[-4.608,13.156],[0,13.093]],"o":[[-1.15,-3.283],[-4.321,-9.433],[-20.723,-24.463],[-62.394,0],[0,62.394],[34.572,0],[8.829,-10.423],[4.096,-11.694],[0,-13.093]],"v":[[106.625,-37.348],[102.739,-46.977],[86.221,-72.965],[0,-112.974],[-112.974,0],[0,112.974],[86.221,72.965],[106.625,37.348],[112.974,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.458,0],[0,0],[0,-3.457],[0,0],[-3.458,0],[0,0],[0,3.457],[0,0]],"o":[[0,0],[-3.458,0],[0,0],[0,3.457],[0,0],[3.458,0],[0,0],[0,-3.457]],"v":[[64.802,-17.804],[-53.181,-17.804],[-59.451,-11.534],[-59.451,25.836],[-53.181,32.106],[64.802,32.106],[71.071,25.836],[71.071,-11.534]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.623,0],[0,0],[0,2.623],[0,0],[-2.623,0],[0,0],[0,-2.623],[0,0]],"o":[[0,0],[-2.623,0],[0,0],[0,-2.623],[0,0],[2.623,0],[0,0],[0,2.623]],"v":[[70.881,36.666],[-59.261,36.666],[-64.011,31.916],[-64.011,-17.614],[-59.261,-22.364],[70.881,-22.364],[75.631,-17.614],[75.631,31.916]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960790157,0.96862745285,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.111,0],[0,0],[0,-6.263],[0,0],[0,0],[0,0]],"o":[[0,0],[-6.111,0],[0,0],[0,0],[0,0],[0,-6.263]],"v":[[95.561,-72.965],[-80.408,-72.965],[-91.472,-61.625],[-91.472,-46.977],[106.625,-46.977],[106.625,-61.625]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.070588238537,0.20000000298,0.29411765933,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-6.111,0],[0,0],[0,6.263],[0,0],[0,0]],"o":[[0,6.263],[0,0],[6.111,0],[0,0],[0,0],[0,0]],"v":[[-91.472,61.625],[-80.408,72.965],[95.561,72.965],[106.625,61.625],[106.625,-46.977],[-91.472,-46.977]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.309803932905,0.674509823322,0.972549021244,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"++++","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[101.537,37.094,0],"ix":2,"l":2},"a":{"a":0,"k":[-24.463,-88.906,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":10,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":50,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":70,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":80,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":100,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":110,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":120,"s":[0,0,100]},{"t":130,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.596,0],[0,0],[0,0],[0,-3.194],[0,0],[0,0],[0,-1.243],[-1.596,0],[0,0],[0,0],[-1.243,0],[0,1.596],[0,0],[0,0],[0,1.243]],"o":[[0,0],[0,0],[0,-3.19],[0,0],[0,0],[-1.596,0],[0,1.241],[0,0],[0,0],[0,1.596],[1.242,0],[0,0],[0,0],[1.596,0],[0,-1.241]],"v":[[-18.355,-91.424],[-21.962,-91.424],[-21.962,-95.032],[-26.961,-95.032],[-26.961,-91.424],[-30.57,-91.424],[-33.002,-88.923],[-30.57,-86.425],[-26.961,-86.425],[-26.961,-82.817],[-24.461,-80.386],[-21.962,-82.817],[-21.962,-86.425],[-18.355,-86.425],[-15.923,-88.926]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.533333361149,0.482352942228,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Ellipes","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[126,126,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-6.663],[6.663,0],[0,6.663],[-6.663,0]],"o":[[0,6.663],[-6.663,0],[0,-6.663],[6.663,0]],"v":[[61.359,-72.965],[49.294,-60.9],[37.229,-72.965],[49.294,-85.03]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0.96862745285,0.800000011921,0.498039215803,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":22,"s":[1,0.533333361149,0.482352972031,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":45,"s":[0.309803932905,0.674509823322,0.972549080849,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":68,"s":[0.917647123337,0.592156887054,0.211764723063,1]},{"t":90,"s":[0.890196084976,0.945098042488,0.984313726425,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"gear 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[15]},{"t":90,"s":[375]}],"ix":10},"p":{"a":0,"k":[145.154,237.027,0],"ix":2,"l":2},"a":{"a":0,"k":[13.654,69.027,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.015,-4.165],[-4.086,0.012],[0.056,4.297],[3.946,-0.013]],"o":[[0.015,4.159],[4.26,-0.013],[-0.05,-3.882],[-4.209,0.014]],"v":[[6.309,68.847],[13.716,76.338],[21.27,68.594],[13.812,61.371]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.816,-0.082],[0.252,1.736],[1.616,0.504],[1.027,-1.139],[1.39,1.123],[0.807,0.724],[-0.984,1.258],[0.887,1.526],[1.285,-0.022],[0.187,2.108],[0.112,0.905],[-1.478,0.195],[-0.448,1.735],[1.116,1.001],[-1.078,1.329],[-0.717,0.813],[-1.311,-1.002],[-1.369,0.721],[0.114,1.915],[-1.379,0.196],[-1.222,0.057],[-0.197,-1.489],[-1.438,-0.466],[-1.261,1.439],[-1.035,-0.768],[-0.967,-0.885],[0.899,-1.15],[-0.718,-1.41],[-1.675,0.116],[-0.226,-1.317],[-0.023,-1.312],[1.329,-0.175],[0.481,-1.717],[-1.139,-1.012],[1.12,-1.417],[0.708,-0.821],[1.194,0.933],[1.529,-0.807],[0.033,-1.554],[1.99,-0.296]],"o":[[-1.953,0.057],[-0.234,-1.609],[-1.53,-0.478],[-1.208,1.339],[-0.844,-0.681],[-1.211,-1.087],[1.061,-1.356],[-0.709,-1.219],[-2.1,0.036],[-0.08,-0.908],[-0.186,-1.503],[1.801,-0.238],[0.374,-1.449],[-1.288,-1.154],[0.683,-0.842],[1.1,-1.246],[1.318,1.006],[1.533,-0.807],[-0.081,-1.352],[1.212,-0.172],[1.52,-0.071],[0.204,1.543],[1.646,0.533],[0.83,-0.947],[1.053,0.781],[1.035,0.948],[-0.994,1.272],[0.759,1.49],[1.301,-0.09],[0.222,1.293],[0.024,1.373],[-1.793,0.236],[-0.4,1.427],[1.352,1.201],[-0.672,0.851],[-0.989,1.147],[-1.363,-1.065],[-1.415,0.748],[-0.042,1.98],[-1.014,0.151]],"v":[[14.124,90.48],[10.971,88.198],[8.449,85.359],[5,86.195],[1.14,86.403],[-1.356,84.316],[-1.851,80.753],[-1.66,76.824],[-4.366,75.217],[-7.473,72.329],[-7.762,69.608],[-5.775,66.587],[-2.834,63.776],[-3.652,60.439],[-3.837,56.646],[-1.757,54.145],[1.788,53.61],[5.389,53.635],[7.734,50.206],[9.95,47.932],[13.607,47.576],[16.359,49.684],[18.75,52.221],[22.834,51.484],[25.87,51.393],[28.91,53.893],[29.256,57.199],[29.126,60.814],[32.325,62.864],[34.725,64.97],[35.098,68.883],[33.206,71.442],[30.236,74.256],[30.971,77.557],[31.18,81.417],[29.107,83.924],[25.604,84.454],[21.682,84.28],[19.669,87.329],[16.981,90.186]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"gear","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":90,"s":[360]}],"ix":10},"p":{"a":0,"k":[139.654,195.027,0],"ix":2,"l":2},"a":{"a":0,"k":[13.654,69.027,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.015,-4.165],[-4.086,0.012],[0.056,4.297],[3.946,-0.013]],"o":[[0.015,4.159],[4.26,-0.013],[-0.05,-3.882],[-4.209,0.014]],"v":[[6.309,68.847],[13.716,76.338],[21.27,68.594],[13.812,61.371]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.816,-0.082],[0.252,1.736],[1.616,0.504],[1.027,-1.139],[1.39,1.123],[0.807,0.724],[-0.984,1.258],[0.887,1.526],[1.285,-0.022],[0.187,2.108],[0.112,0.905],[-1.478,0.195],[-0.448,1.735],[1.116,1.001],[-1.078,1.329],[-0.717,0.813],[-1.311,-1.002],[-1.369,0.721],[0.114,1.915],[-1.379,0.196],[-1.222,0.057],[-0.197,-1.489],[-1.438,-0.466],[-1.261,1.439],[-1.035,-0.768],[-0.967,-0.885],[0.899,-1.15],[-0.718,-1.41],[-1.675,0.116],[-0.226,-1.317],[-0.023,-1.312],[1.329,-0.175],[0.481,-1.717],[-1.139,-1.012],[1.12,-1.417],[0.708,-0.821],[1.194,0.933],[1.529,-0.807],[0.033,-1.554],[1.99,-0.296]],"o":[[-1.953,0.057],[-0.234,-1.609],[-1.53,-0.478],[-1.208,1.339],[-0.844,-0.681],[-1.211,-1.087],[1.061,-1.356],[-0.709,-1.219],[-2.1,0.036],[-0.08,-0.908],[-0.186,-1.503],[1.801,-0.238],[0.374,-1.449],[-1.288,-1.154],[0.683,-0.842],[1.1,-1.246],[1.318,1.006],[1.533,-0.807],[-0.081,-1.352],[1.212,-0.172],[1.52,-0.071],[0.204,1.543],[1.646,0.533],[0.83,-0.947],[1.053,0.781],[1.035,0.948],[-0.994,1.272],[0.759,1.49],[1.301,-0.09],[0.222,1.293],[0.024,1.373],[-1.793,0.236],[-0.4,1.427],[1.352,1.201],[-0.672,0.851],[-0.989,1.147],[-1.363,-1.065],[-1.415,0.748],[-0.042,1.98],[-1.014,0.151]],"v":[[14.124,90.48],[10.971,88.198],[8.449,85.359],[5,86.195],[1.14,86.403],[-1.356,84.316],[-1.851,80.753],[-1.66,76.824],[-4.366,75.217],[-7.473,72.329],[-7.762,69.608],[-5.775,66.587],[-2.834,63.776],[-3.652,60.439],[-3.837,56.646],[-1.757,54.145],[1.788,53.61],[5.389,53.635],[7.734,50.206],[9.95,47.932],[13.607,47.576],[16.359,49.684],[18.75,52.221],[22.834,51.484],[25.87,51.393],[28.91,53.893],[29.256,57.199],[29.126,60.814],[32.325,62.864],[34.725,64.97],[35.098,68.883],[33.206,71.442],[30.236,74.256],[30.971,77.557],[31.18,81.417],[29.107,83.924],[25.604,84.454],[21.682,84.28],[19.669,87.329],[16.981,90.186]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Gear_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":90,"s":[-360]}],"ix":10},"p":{"a":0,"k":[108.05,216.774,0],"ix":2,"l":2},"a":{"a":0,"k":[-17.95,90.774,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.375,0.047],[0.004,3.262],[3.428,-0.055],[-0.026,-3.347]],"o":[[3.291,-0.046],[-0.005,-3.425],[-3.372,0.055],[0.026,3.353]],"v":[[-17.807,96.659],[-11.814,90.628],[-17.999,84.557],[-23.99,90.648]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.001,-0.013],[0.449,0.07],[0.1,1.364],[1.115,0.469],[1.008,-0.86],[1.077,0.951],[0.49,0.555],[-0.993,1.128],[0.681,0.922],[0.037,0.193],[0.902,0.059],[0.022,1.882],[0,0.428],[-1.948,0.144],[-0.319,0.683],[1.204,1.287],[-0.53,0.797],[-0.604,0.562],[-1.335,-1.135],[-0.634,0.428],[-0.081,0.024],[-0.118,1.812],[-0.975,0.055],[-0.937,-0.064],[-0.089,-1.403],[-0.851,-0.155],[-0.094,-0.061],[-1.225,0.991],[-0.854,-0.791],[-0.512,-0.61],[0.958,-1.111],[-0.263,-0.798],[-1.671,-0.135],[-0.132,-0.936],[0.144,-0.961],[1.527,-0.089],[0.335,-0.673],[-1.241,-1.372],[0.545,-0.766],[0.683,-0.602],[1.09,0.978],[0.986,-0.349],[0.102,-1.568],[1.411,-0.142],[0.342,-0.003]],"o":[[-0.454,-0.037],[-1.374,-0.214],[-0.086,-1.17],[-1.164,-0.49],[-1.085,0.925],[-0.555,-0.49],[-0.994,-1.127],[0.723,-0.821],[-0.115,-0.155],[-0.166,-0.853],[-1.86,-0.123],[-0.005,-0.428],[-0.002,-1.986],[0.861,-0.064],[0.64,-1.372],[-0.652,-0.697],[0.463,-0.696],[1.283,-1.193],[0.603,0.513],[0.07,-0.048],[1.449,-0.428],[0.059,-0.909],[0.938,-0.053],[1.271,0.087],[0.057,0.9],[0.11,0.02],[1.164,0.756],[0.898,-0.726],[0.585,0.542],[0.873,1.04],[-0.574,0.665],[0.475,1.441],[0.95,0.077],[0.135,0.959],[-0.212,1.411],[-0.781,0.045],[-0.71,1.427],[0.602,0.666],[-0.534,0.75],[-1.092,0.962],[-0.847,-0.759],[-1.337,0.474],[-0.079,1.217],[-0.339,0.034],[-0.001,0.013]],"v":[[-18.099,108.227],[-19.46,108.111],[-21.714,105.831],[-23.389,103.638],[-26.336,103.939],[-29.589,103.753],[-31.162,102.179],[-31.252,98.698],[-30.959,96.238],[-31.178,95.683],[-32.713,94.43],[-35.4,91.464],[-35.407,90.18],[-32.673,87.073],[-31.273,85.914],[-31.533,82.079],[-31.394,79.606],[-29.701,77.796],[-25.888,77.669],[-24.143,77.85],[-23.915,77.734],[-21.229,74.878],[-19.28,73.366],[-16.457,73.365],[-14.218,75.753],[-12.943,77.278],[-12.624,77.398],[-9.205,77.297],[-6.317,77.74],[-4.656,79.465],[-4.738,82.807],[-4.992,84.792],[-2.193,87.3],[-0.6,89.205],[-0.595,92.107],[-3.171,94.371],[-4.59,95.433],[-4.396,99.474],[-4.57,101.866],[-6.459,103.843],[-9.868,103.917],[-12.364,103.623],[-14.611,106.225],[-17.07,108.175],[-18.096,108.188]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"BG","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[126,126,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-62.394],[62.394,0],[0,62.394],[-62.394,0]],"o":[[0,62.394],[-62.394,0],[0,-62.394],[62.394,0]],"v":[[112.974,0],[0,112.974],[-112.974,0],[0,-112.974]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.890196084976,0.945098042488,0.984313726425,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0}],"markers":[],"chars":[{"ch":"F","size":26.6488609313965,"style":"Bold","w":60.7,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[6.848,-70.596],[6.848,0],[25.278,0],[25.278,-25.479],[56.9,-25.479],[56.9,-40.182],[25.278,-40.182],[25.278,-55.893],[59.518,-55.893],[59.619,-70.596]],"c":true},"ix":2},"nm":"F","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"F","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Montserrat"},{"ch":"B","size":26.6488609313965,"style":"Bold","w":71.6,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[16.013,0],[0,0],[0,0],[0,0],[0,12.085],[8.963,1.813],[0,7.352]],"o":[[0,0],[0,0],[0,0],[16.617,0],[0,-9.064],[7.452,-2.014],[0,-10.876]],"v":[[40.384,-70.596],[6.848,-70.596],[6.848,0],[41.693,0],[68.884,-19.638],[54.382,-37.463],[66.568,-52.771]],"c":true},"ix":2},"nm":"B","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[5.136,0],[0,0],[0,0],[0,0],[0,-4.23]],"o":[[0,0],[0,0],[0,0],[5.136,-0.101],[0,4.431]],"v":[[39.377,-42.499],[25.278,-42.499],[25.278,-56.195],[39.377,-56.195],[47.635,-49.548]],"c":true},"ix":2},"nm":"B","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[6.445,0],[0,0],[0,0],[0,0],[0,-4.431]],"o":[[0,0],[0,0],[0,0],[6.445,-0.101],[0,4.834]],"v":[[39.377,-14.301],[25.278,-14.301],[25.278,-29.105],[39.377,-29.105],[49.85,-21.954]],"c":true},"ix":2},"nm":"B","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"B","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Montserrat"},{"ch":"5","size":26.6488609313965,"style":"Bold","w":61.7,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.511,-0.101],[0,0],[0,0],[0,0],[0,0],[0,0],[-3.726,0],[0,-5.338],[7.15,0],[5.539,5.841],[0,0],[-9.467,0],[0,14.905],[16.617,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[4.431,-0.302],[7.05,0],[0,5.74],[-6.445,0],[0,0],[7.654,5.338],[17.422,0],[0,-12.589],[-1.41,0]],"v":[[24.774,-45.016],[24.774,-55.792],[55.289,-55.792],[55.289,-70.697],[7.855,-70.697],[7.855,-30.414],[27.594,-30.817],[38.672,-22.458],[27.493,-13.495],[9.064,-22.357],[1.712,-8.057],[29.709,0.806],[58.511,-23.767],[31.119,-45.117]],"c":true},"ix":2},"nm":"5","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Montserrat"},{"ch":"D","size":26.6488609313965,"style":"Bold","w":76.6,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.357,0],[0,0],[0,0],[0,0],[0,21.048]],"o":[[0,0],[0,0],[0,0],[22.861,0],[0,-20.947]],"v":[[37.262,-70.596],[6.848,-70.596],[6.848,0],[36.557,0],[74.826,-35.349]],"c":true},"ix":2},"nm":"D","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[10.675,0],[0,0],[0,0],[0,0],[0,-12.186]],"o":[[0,0],[0,0],[0,0],[11.179,0],[0,12.085]],"v":[[37.766,-14.905],[25.278,-14.905],[25.278,-55.591],[36.859,-55.591],[55.994,-35.147]],"c":true},"ix":2},"nm":"D","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"D","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Montserrat"},{"ch":"0","size":26.6488609313965,"style":"Bold","w":61.7,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[17.725,0],[0,-23.062],[-17.926,0],[0,23.062]],"o":[[-17.926,0],[0,23.062],[17.725,0],[0,-23.062]],"v":[[31.119,-71.1],[3.424,-35.349],[31.119,0.504],[58.713,-35.349]],"c":true},"ix":2},"nm":"0","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-7.15,0],[0,-16.214],[7.05,0],[0,16.113]],"o":[[7.05,0],[0,16.113],[-7.15,0],[0,-16.214]],"v":[[31.119,-58.209],[41.089,-35.349],[31.119,-12.488],[21.048,-35.349]],"c":true},"ix":2},"nm":"0","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"0","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Montserrat"},{"ch":"1","size":26.6488609313965,"style":"Bold","w":61.7,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.265,-70.596],[9.265,-55.49],[22.861,-55.49],[22.861,0],[41.29,0],[41.29,-70.596]],"c":true},"ix":2},"nm":"1","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Montserrat"},{"ch":"|","size":26.6488609313965,"style":"Bold","w":30.2,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[8.56,-80.768],[8.56,10.977],[21.854,10.977],[21.854,-80.768]],"c":true},"ix":2},"nm":"|","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"|","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Montserrat"}]} \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/values-night/themes.xml b/android/HowAboutTrip/app/src/main/res/values-night/themes.xml index 7496c57d..95d02503 100644 --- a/android/HowAboutTrip/app/src/main/res/values-night/themes.xml +++ b/android/HowAboutTrip/app/src/main/res/values-night/themes.xml @@ -1,12 +1,31 @@ + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/values/strings.xml b/android/HowAboutTrip/app/src/main/res/values/strings.xml index 1eb546af..9cc5ec15 100644 --- a/android/HowAboutTrip/app/src/main/res/values/strings.xml +++ b/android/HowAboutTrip/app/src/main/res/values/strings.xml @@ -3,4 +3,33 @@ HowAboutTrip에서\n여행 계획을 세우는 건 어떤가요? google login How About Trip + 입력 완료 + How About Trip을 처음 사용하시는 군요! + 신규 가입자는 추가 정보를 입력하셔야 합니다.\n이름은 본인 실명을 입력하셔야 합니다. + 이름 + 본인 명의 이름으로 작성 + 전화번호 + 010-1234-5678 + 생년 월일 + 입력 + 미입력 + 2024 + 01 + SUN + MON + TUE + WED + THU + FRI + SAT + 확정 + 초기화 + saveCheck + 항공 숙박 + 일정 조회 + 사진 기록 + My + + Hello blank fragment + Bearer %1$s \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/values/themes.xml b/android/HowAboutTrip/app/src/main/res/values/themes.xml index 7496c57d..eb54e315 100644 --- a/android/HowAboutTrip/app/src/main/res/values/themes.xml +++ b/android/HowAboutTrip/app/src/main/res/values/themes.xml @@ -9,4 +9,23 @@ @color/black false + + + + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/app/src/main/res/xml/network_security_config.xml b/android/HowAboutTrip/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 00000000..176d19a4 --- /dev/null +++ b/android/HowAboutTrip/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/android/HowAboutTrip/build.gradle.kts b/android/HowAboutTrip/build.gradle.kts index 591e568c..817165d5 100644 --- a/android/HowAboutTrip/build.gradle.kts +++ b/android/HowAboutTrip/build.gradle.kts @@ -5,7 +5,7 @@ buildscript { } // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.2.1" apply false + id("com.android.application") version "8.2.2" apply false id("org.jetbrains.kotlin.android") version "1.9.10" apply false id("com.google.gms.google-services") version "4.4.0" apply false kotlin("kapt") version "1.9.22" diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index 52dd9f22..00000000 --- a/backend/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -# Elastic Beanstalk Files -.elasticbeanstalk/* -!.elasticbeanstalk/*.cfg.yml -!.elasticbeanstalk/*.global.yml