diff --git a/app/build.gradle b/app/build.gradle
index bf461b0..40bcdf0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,7 +3,7 @@ plugins {
id 'org.jetbrains.kotlin.android'
id 'com.google.gms.google-services' // Google Services Gradle Plugin
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' // Secrets Gradle Plugin
- id 'androidx.navigation.safeargs.kotlin' // Navigation Safe Args
+ id "androidx.navigation.safeargs"
}
android {
@@ -11,7 +11,7 @@ android {
defaultConfig {
applicationId "jp.ac.okinawa_ct.nitoc_ict.aroa"
- minSdk 31
+ minSdk 26
targetSdk 32
versionCode 1
versionName "1.0"
@@ -42,8 +42,6 @@ dependencies {
// 基本的なライブラリ
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.5.0'
- implementation 'androidx.activity:activity-ktx:1.5.1'
- implementation 'androidx.fragment:fragment-ktx:1.5.2'
// レイアウト系
implementation 'com.google.android.material:material:1.6.1'
@@ -52,16 +50,11 @@ dependencies {
// ライフサイクル対応コンポーネント
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
- implementation 'androidx.legacy:legacy-support-v4:1.0.0'
// Navigation
- def nav_version = "2.5.2"
- implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
- implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
- implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
-
- // Preferences DataStore
- implementation "androidx.datastore:datastore-preferences:1.0.0"
+ implementation 'androidx.navigation:navigation-fragment-ktx:2.5.1'
+ implementation 'androidx.navigation:navigation-ui-ktx:2.5.1'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
@@ -69,10 +62,18 @@ dependencies {
// Google Maps SDK
implementation 'com.google.android.gms:play-services-maps:18.1.0'
+ implementation "com.google.maps:google-maps-services:0.2.11"
+ implementation 'com.google.maps.android:android-maps-utils:2.2.0'
+
+ //位置情報関係
+ implementation 'com.google.android.gms:play-services-location:16.0.0'
+// implementation 'com.google.android.libraries.places:places:1.1.0'
// Firebase
implementation platform('com.google.firebase:firebase-bom:30.2.0') // Firebase BoM
implementation 'com.google.firebase:firebase-analytics-ktx' // Firebase Analytics
implementation 'com.google.firebase:firebase-firestore-ktx' // Firebase FireStore
+ implementation "androidx.datastore:datastore-preferences:1.0.0"
+
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 58135cd..99a7b8d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,13 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
package="jp.ac.okinawa_ct.nitoc_ict.aroa">
-
-
-
-
-
+
+
+ tools:targetApi="31">
+
+ android:exported="true"
+ android:screenOrientation="portrait">
-
-
-
+
+
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Record.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Record.kt
index 7c47530..9eecea6 100644
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Record.kt
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Record.kt
@@ -1,5 +1,7 @@
package jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto
+import java.util.*
+
/**
* トライアルの記録を表現するクラス
*
@@ -9,7 +11,10 @@ package jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto
sealed class Record {
abstract val userId: String
abstract val trialId: String
+ abstract val trialName: String
+ abstract val date: String
abstract val rank: Int
+ abstract val recordId: String
/**
* マラソンのトライアルの記録を表現するクラス
@@ -19,8 +24,12 @@ sealed class Record {
data class MarathonRecord(
override val userId: String,
override val trialId: String,
+ override val trialName: String,
+ override val date: String,
+ val distance: Long,
val time: Long,
override val rank: Int = -1,
+ override val recordId: String = UUID.randomUUID().toString(),
): Record()
/**
@@ -31,7 +40,10 @@ sealed class Record {
data class DanglingRecord(
override val userId: String,
override val trialId: String,
+ override val trialName: String,
+ override val date: String,
val time: Long,
override val rank: Int = -1,
+ override val recordId: String,
): Record()
}
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Trial.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Trial.kt
index 9882019..b14f23e 100644
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Trial.kt
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/dto/Trial.kt
@@ -15,6 +15,7 @@ sealed class Trial {
abstract val name: String
abstract val authorUserId: String
abstract val position: LatLng
+ abstract val createDate: String
abstract val id: String
/**
@@ -27,6 +28,7 @@ sealed class Trial {
override val authorUserId: String,
override val position: LatLng,
val course: List,
+ override val createDate: String,
override val id: String = UUID.randomUUID().toString(),
) : Trial()
@@ -40,6 +42,7 @@ sealed class Trial {
override val authorUserId: String,
override val position: LatLng,
val goalCount: Int,
+ override val createDate: String,
override val id: String = UUID.randomUUID().toString(),
) : Trial()
}
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/RecordRepository.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/RecordRepository.kt
index 3fb8b01..32032cc 100644
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/RecordRepository.kt
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/RecordRepository.kt
@@ -26,7 +26,7 @@ interface RecordRepository {
* @param startRank 何位から取得するか. 1以上である必要がある。
* @param maxResult startRankで指定された順位から最大でいくつの[Record]を取得するか
*/
- fun getRecords(trial: Trial, startRank: Int, maxResult: Int): Flow>>
+ fun getRecords(trialId: String, startRank: Int, maxResult: Int): Flow>>
/**
* 指定された[Trial]のランキングに[Record]を追加する.すでに同じユーザーの記録がある場合は上書きする
@@ -37,4 +37,8 @@ interface RecordRepository {
* @return データベースへの送信委成功した時は実際のランキングが保存された[Record]
*/
fun createOrUpdateRecord(trial: Trial, record: Record): Flow>
+
+ fun getMyRecords(userId: String): Flow>>
+
+ fun getRecordByTrialIdAndRecordId(trialId: String, recordId: String): Flow>
}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/RecordRepositoryDummy.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/RecordRepositoryDummy.kt
new file mode 100644
index 0000000..ffbdc87
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/RecordRepositoryDummy.kt
@@ -0,0 +1,141 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository
+
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Record
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Trial
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.*
+
+class RecordRepositoryDummy: RecordRepository {
+ companion object {
+ private val trial1RecordList = mutableListOf(
+ Record.MarathonRecord(
+ "サイス", "testTrialID_1","沖縄高専外周コース1","2022年10月15日",487,140,2,"testRecordId1"
+ ),
+ Record.MarathonRecord(
+ "知念","testTrialID_1","沖縄高専外周コース1","2022年10月14日",487,150,3,"testRecordId2"
+ ),
+ Record.MarathonRecord(
+ "ひじかた","testTrialID_1","沖縄高専外周コース1","2022年10月13日",487,110,1,"testRecordId3"
+ ),
+ )
+ private val trial2RecordList = mutableListOf(
+ Record.MarathonRecord(
+ "サイス", "testTrialID_2","沖縄高専外周コース2","2022年10月15日",975,310,2,"testRecordId1"
+ ),
+ Record.MarathonRecord(
+ "知念","testTrialID_2","沖縄高専外周コース2","2022年10月14日",975,340,3,"testRecordId2"
+ ),
+ Record.MarathonRecord(
+ "ひじかた","testTrialID_2","沖縄高専外周コース2","2022年10月13日",975,250,1,"testRecordId3"
+ ),
+ )
+ private val trial3RecordList = mutableListOf(
+ Record.MarathonRecord(
+ "サイス", "testTrialID_3","沖縄高専外周コース3","2022年10月15日",616,210,2,"testRecordId1"
+ ),
+ Record.MarathonRecord(
+ "知念","testTrialID_3","沖縄高専外周コース3","2022年10月14日",616,290,3,"testRecordId2"
+ ),
+ Record.MarathonRecord(
+ "ひじかた","testTrialID_3","沖縄高専外周コース3","2022年10月13日",616,180,1,"testRecordId3"
+ ),
+ )
+
+ private val myRecordList = mutableListOf(
+ Record.MarathonRecord(
+ "ひじかた","testTrialID_1","沖縄高専外周コース1","2022年10月13日",487,110,1,"testRecordId1"
+ ),
+ Record.MarathonRecord(
+ "ひじかた","testTrialID_2","沖縄高専外周コース2","2022年10月13日",975,250,1,"testRecordId2"
+ ),
+ Record.MarathonRecord(
+ "ひじかた","testTrialID_3","沖縄高専外周コース3","2022年10月13日",616,180,1,"testRecordId3"
+ ),
+ )
+ }
+
+
+ override fun getRecordByUserId(trial: Trial, userId: String): Flow> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getRecords(
+ trialId: String,
+ startRank: Int,
+ maxResult: Int
+ ): Flow>> =
+ flow>> {
+ delay(1000)
+ val comparator : Comparator = compareBy { it.rank }
+ when(trialId) {
+ trial1RecordList.get(0).trialId -> emit(Result.Success(trial1RecordList.sortedWith(comparator)))
+ trial2RecordList.get(0).trialId -> emit(Result.Success(trial2RecordList.sortedWith(comparator)))
+ trial3RecordList.get(0).trialId -> emit(Result.Success(trial3RecordList.sortedWith(comparator)))
+ }
+ }.catch {
+ when(it) {
+ is Exception -> {
+ emit(Result.Error(true, it))
+ }
+ }
+ }.onStart {
+ emit(Result.Loading)
+ }.flowOn(Dispatchers.IO)
+
+ override fun createOrUpdateRecord(trial: Trial, record: Record): Flow> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getMyRecords(userId: String): Flow>> =
+ flow>> {
+ delay(1000)
+ emit(Result.Success(myRecordList))
+ }.catch {
+ when(it) {
+ is Exception -> {
+ emit(Result.Error(true, it))
+ }
+ }
+ }.onStart {
+ emit(Result.Loading)
+ }.flowOn(Dispatchers.IO)
+
+ override fun getRecordByTrialIdAndRecordId(trialId: String, recordId: String): Flow> =
+ flow> {
+ delay(1000)
+ when(trialId) {
+ trial1RecordList.get(0).trialId -> {
+ for (data in trial1RecordList) {
+ if (data.recordId == recordId) {
+ emit(Result.Success(data))
+ }
+ }
+ }
+ trial2RecordList.get(0).trialId -> {
+ for (data in trial2RecordList) {
+ if (data.recordId == recordId) {
+ emit(Result.Success(data))
+ }
+ }
+ }
+ trial3RecordList.get(0).trialId -> {
+ for (data in trial3RecordList) {
+ if (data.recordId == recordId) {
+ emit(Result.Success(data))
+ }
+ }
+ }
+ }
+ }.catch {
+ when(it) {
+ is Exception -> {
+ emit(Result.Error(true, it))
+ }
+ }
+ }.onStart {
+ emit(Result.Loading)
+ }.flowOn(Dispatchers.IO)
+}
+
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/TrialRepositoryDummy.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/TrialRepositoryDummy.kt
index b0baa28..e526fea 100644
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/TrialRepositoryDummy.kt
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/data/repository/TrialRepositoryDummy.kt
@@ -13,55 +13,63 @@ import kotlinx.coroutines.flow.*
*/
class TrialRepositoryDummy : TrialRepository {
- private val testDataList = mutableListOf(
- Trial.Marathon(
- "テストマラソントライアル_1",
- "testUserID",
- LatLng(26.526230, 128.030372), // 沖縄高専
- listOf(
- LatLng(26.526230, 128.030372),
- LatLng(26.526227, 128.030645),
- LatLng(26.526424, 128.030645),
- LatLng(26.526424, 128.030372),
- LatLng(26.526230, 128.030372),
- ), // 沖縄高専の敷地内を回るコース
- "testTrialID_1",
- ),
- Trial.Marathon(
- "テストマラソントライアル_2",
- "testUserID",
- LatLng(26.526347, 128.029209), // 沖縄高専
- listOf(
- LatLng(26.526347, 128.029209),
- LatLng(26.526230, 128.030372),
- LatLng(26.526227, 128.030645),
- LatLng(26.526424, 128.030645),
- LatLng(26.526424, 128.030372),
- LatLng(26.526347, 128.029209),
- ), // 沖縄高専の敷地内を回るコース
- "testTrialID_2",
- ),
- Trial.Marathon(
- "テストマラソントライアル_3",
- "testUserID",
- LatLng(26.525823, 128.031147), // 沖縄高専
- listOf(
- LatLng(26.525823, 128.031147),
- LatLng(26.526230, 128.030372),
- LatLng(26.526227, 128.030645),
- LatLng(26.526424, 128.030645),
- LatLng(26.526424, 128.030372),
- LatLng(26.525823, 128.031147),
- ), // 沖縄高専の敷地内を回るコース
- "testTrialID_3",
- ),
-
+ companion object {
+ private val testDataList = mutableListOf(
+ Trial.Marathon(
+ "沖縄高専外周コース1",
+ "ひじかた",
+ LatLng(26.526230, 128.030372), // 沖縄高専
+ listOf(
+ LatLng(26.526230, 128.030372),
+ LatLng(26.526227, 128.030645),
+ LatLng(26.526424, 128.030645),
+ LatLng(26.526424, 128.030372),
+ LatLng(26.526230, 128.030372),
+ ), // 沖縄高専の敷地内を回るコース
+ "2022月10月15日",
+ "testTrialID_1"
+ ),
+ Trial.Marathon(
+ "沖縄高専外周コース2",
+ "ひじかた",
+ LatLng(26.526347, 128.029209), // 沖縄高専
+ listOf(
+ LatLng(26.526347, 128.029209),
+ LatLng(26.526230, 128.030372),
+ LatLng(26.526227, 128.030645),
+ LatLng(26.526424, 128.030645),
+ LatLng(26.526424, 128.030372),
+ LatLng(26.526347, 128.029209),
+ ), // 沖縄高専の敷地内を回るコース
+ "2022月10月15日",
+ "testTrialID_2",
+ ),
+ Trial.Marathon(
+ "沖縄高専外周コース3",
+ "ひじかた",
+ LatLng(26.525823, 128.031147), // 沖縄高専
+ listOf(
+ LatLng(26.525823, 128.031147),
+ LatLng(26.526230, 128.030372),
+ LatLng(26.526227, 128.030645),
+ LatLng(26.526424, 128.030645),
+ LatLng(26.526424, 128.030372),
+ LatLng(26.525823, 128.031147),
+ ), // 沖縄高専の敷地内を回るコース
+ "2022月10月15日",
+ "testTrialID_3",
+ ),
)
+ }
override fun getTrialById(id: String): Flow> =
flow> {
delay(1000) // ネットワーク処理の遅延の際限の為、1000ms 待つ
- emit(Result.Success(testDataList[0]))
+ for (data in testDataList) {
+ if (data.id == id) {
+ emit(Result.Success(data))
+ }
+ }
Log.d("TrialRepositoryDummy", testDataList[0].toString())
}.catch {
// 本来はここでエラー処理をする
@@ -79,7 +87,7 @@ class TrialRepositoryDummy : TrialRepository {
flow>> {
delay(1000) // ネットワーク処理の遅延の際限の為、1000ms 待つ
emit(Result.Success(testDataList))
- Log.d("TrialRepositoryDummy", testDataList.toString())
+ Log.d("TrialRepositoryDummy", "AddTrialFragment:${testDataList}")
}.catch {
// 本来はここでエラー処理をする
when (it) {
@@ -99,9 +107,9 @@ class TrialRepositoryDummy : TrialRepository {
override fun createTrial(trial: Trial): Flow> =
flow> {
testDataList.add(trial)
- delay(500)
+ delay(50)
emit(Result.Success(trial))
- Log.d("TrialRepositoryDummy", testDataList.toString())
+ Log.d("TrialRepositoryDummy", "createTrial:${testDataList}")
}.onStart {
emit(Result.Loading)
Log.d("TrialRepositoryDummy", "Updating...")
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/MainActivity.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/MainActivity.kt
index 3f871ea..5a7bf20 100644
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/MainActivity.kt
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/MainActivity.kt
@@ -3,7 +3,6 @@ package jp.ac.okinawa_ct.nitoc_ict.aroa.ui
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
-import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
@@ -30,7 +29,7 @@ class MainActivity : AppCompatActivity() {
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
- R.id.navigation_home, R.id.navigation_add_trial, R.id.navigation_check_record
+ R.id.navigation_home, R.id.navigation_create_trial, R.id.navigation_check_record
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/AddTrialFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/AddTrialFragment.kt
deleted file mode 100644
index f116bcd..0000000
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/AddTrialFragment.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentAddTrialBinding
-
-class AddTrialFragment : Fragment() {
-
- private var _binding: FragmentAddTrialBinding? = null
-
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- val dashboardViewModel =
- ViewModelProvider(this).get(AddTrialViewModel::class.java)
-
- _binding = FragmentAddTrialBinding.inflate(inflater, container, false)
- val root: View = binding.root
-
- val textView: TextView = binding.textAddTrial
- dashboardViewModel.text.observe(viewLifecycleOwner) {
- textView.text = it
- }
- return root
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/AddTrialViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/AddTrialViewModel.kt
deleted file mode 100644
index 9bee1e0..0000000
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/AddTrialViewModel.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-
-class AddTrialViewModel : ViewModel() {
-
- private val _text = MutableLiveData().apply {
- value = "This is addTrial Fragment"
- }
- val text: LiveData = _text
-}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/CreatedTrialAdapter.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/CreatedTrialAdapter.kt
new file mode 100644
index 0000000..b1f5724
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/CreatedTrialAdapter.kt
@@ -0,0 +1,58 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Trial
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.ListItemTrialBinding
+
+typealias OnItemClickListener = (view: View, position: Int) -> Unit
+
+class CreatedTrialAdapter(
+ context: Context
+) : ListAdapter(ITEM_CALLBACK) {
+ private val inflater = LayoutInflater.from(context)
+
+ private var onItemClickListener: OnItemClickListener? = null
+
+ class BindingHolder(
+ val binding: ListItemTrialBinding
+ ) : RecyclerView.ViewHolder(binding.root)
+ companion object {
+ val ITEM_CALLBACK = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: Trial,
+ newItem: Trial
+ ): Boolean = oldItem.id == newItem.id
+
+ override fun areContentsTheSame(
+ oldItem: Trial,
+ newItem: Trial
+ ): Boolean = oldItem == newItem
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder {
+
+ val binding = ListItemTrialBinding.inflate(inflater, parent, false)
+ return BindingHolder(binding)
+ }
+
+ override fun onBindViewHolder(bindingHolder: BindingHolder, position: Int) {
+ val current = getItem(position)
+ bindingHolder.binding.trialName.text = current.name
+ bindingHolder.binding.trialMakeDate.text = current.createDate
+ bindingHolder.binding.itemViewGroup.setOnClickListener {
+ onItemClickListener?.invoke(it,position)
+ }
+ }
+
+ fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
+ this.onItemClickListener = onItemClickListener
+ }
+}
+
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/DirectionsApiHelper.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/DirectionsApiHelper.kt
new file mode 100644
index 0000000..11f6700
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/DirectionsApiHelper.kt
@@ -0,0 +1,68 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial
+
+import android.util.Log
+import androidx.annotation.Nullable
+import com.google.maps.DirectionsApi
+import com.google.maps.GeoApiContext
+import com.google.maps.model.DirectionsResult
+import com.google.maps.model.TravelMode
+import com.google.maps.model.Unit
+import jp.ac.okinawa_ct.nitoc_ict.aroa.BuildConfig
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.util.*
+import com.google.maps.model.LatLng as MapsLatLng
+
+class DirectionsApiHelper {
+ /**
+ * 経路APIを実行する.
+ *
+ * @param context コンテキスト
+ * @param origin 出発地点
+ * @param destination 到着地点
+ * @return 取得成功: [com.google.maps.model.DirectionsResult] 失敗: null
+ */
+ @Nullable
+ suspend fun execute(origin: MapsLatLng?, destination: MapsLatLng?, waypoints: String): DirectionsResult? {
+ return withContext(Dispatchers.IO) {
+ // Mapキーの取得.
+ val apiContext = GeoApiContext.Builder()
+ .apiKey(BuildConfig.MAPS_API_KEY).build()
+
+ // API実行.
+ kotlin.runCatching {
+ DirectionsApi
+ .newRequest(apiContext)
+ .mode(TravelMode.WALKING)
+ .units(Unit.METRIC)
+ .language(Locale.JAPAN.language)
+ .origin(origin)
+ .destination(destination)
+ .waypoints(waypoints)
+ .await()
+ }.getOrNull()
+ }
+ }
+
+ @Nullable
+ suspend fun onlyOriginDestExecute(origin: MapsLatLng?, destination: MapsLatLng?): DirectionsResult? {
+ return withContext(Dispatchers.IO) {
+ // Mapキーの取得.
+ val apiContext = GeoApiContext.Builder()
+ .apiKey(BuildConfig.MAPS_API_KEY).build()
+
+ Log.i("onlyOriginDestExecute","${origin.toString()},${destination.toString()}")
+ // API実行.
+ kotlin.runCatching {
+ DirectionsApi
+ .newRequest(apiContext)
+ .mode(TravelMode.WALKING)
+ .units(Unit.METRIC)
+ .language(Locale.JAPAN.language)
+ .origin(origin)
+ .destination(destination)
+ .await()
+ }.getOrNull()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/dest/AddTrialDestFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/dest/AddTrialDestFragment.kt
new file mode 100644
index 0000000..70916d4
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/dest/AddTrialDestFragment.kt
@@ -0,0 +1,208 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.dest
+
+import android.app.AlertDialog
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.*
+import com.google.maps.android.PolyUtil
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentAddTrialDestBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.util.ConverterVectorToBitmap
+import java.util.*
+
+class AddTrialDestFragment : Fragment() {
+
+ companion object {
+ private const val ZOOM_SIZE = 14f
+ private const val POLYLINE_WIDTH = 12f
+ }
+
+ private var map: GoogleMap? = null
+ private lateinit var viewModel: AddTrialDestViewModel
+ private var polyline: Polyline? = null
+
+ private lateinit var _binding: FragmentAddTrialDestBinding
+
+ private val binding get() = _binding
+
+ private val callback = OnMapReadyCallback { googleMap ->
+ map = googleMap
+ moveCamera()
+ setMapLongClick(googleMap)
+ setOnMarkerDrag(googleMap)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ _binding = FragmentAddTrialDestBinding.inflate(inflater, container, false)
+ val args = AddTrialDestFragmentArgs.fromBundle(
+ requireArguments()
+ )
+ viewModel = ViewModelProvider(this).get(AddTrialDestViewModel::class.java)
+ viewModel.setOrigin(args.originLatLng)
+ binding.nextButton.setOnClickListener {
+ if (viewModel.dest.value != null) {
+ viewModel.navStart()
+ }
+ }
+
+ val builder = AlertDialog.Builder(requireContext())
+ builder.setTitle("トライアルを作成").setMessage("ゴール地点を設定")
+ .setPositiveButton("ok",null)
+ builder.show()
+
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
+ mapFragment?.getMapAsync(callback)
+ observeLiveData()
+ }
+
+ private fun observeLiveData() {
+ viewModel.directionsResult.observe(viewLifecycleOwner, androidx.lifecycle.Observer{
+ Log.i("DestFragment", "directionsResult:${it.toString()}")
+ updatePolyline(it, map)
+ })
+
+ viewModel.navFrag.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+ if (it) {
+ val action =
+ AddTrialDestFragmentDirections.actionNavigationAddTrialDestToNavigationAddTrialMaps(
+ LatLng(
+ viewModel.origin.value!!.latitude,
+ viewModel.origin.value!!.longitude
+ ),
+ LatLng(viewModel.dest.value!!.latitude, viewModel.dest.value!!.longitude)
+ )
+ this.findNavController().navigate(action)
+ viewModel.navCompleted()
+ }
+ })
+ }
+
+ //カメラを移動
+ private fun moveCamera() {
+ // Add a marker in Sydney and move the camera
+ val origin = LatLng(viewModel.origin.value!!.latitude, viewModel.origin.value!!.longitude)
+ map?.apply {
+ addMarker(MarkerOptions()
+ .position(origin)
+ .title("Marker in Origin")
+ .icon(BitmapDescriptorFactory.fromBitmap(
+ ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_flag_circle_origin_36)))
+ .anchor(0.5F,0.5F))
+ moveCamera(CameraUpdateFactory.newLatLngZoom(origin, ZOOM_SIZE))
+ }
+ }
+
+ //マップをロングクリック時にマーカーを追加
+ private fun setMapLongClick(map: GoogleMap) {
+ map.setOnMapLongClickListener{latLng ->
+ val snippet = String.format(
+ Locale.getDefault(),
+ "Lat: %1$.5f, Long: %2$.5f",
+ latLng.latitude,
+ latLng.longitude
+ )
+ //マップをクリア、originのマーカーを追加
+ map.clear()
+
+ map.addMarker(
+ MarkerOptions()
+ .position(
+ LatLng(
+ viewModel.origin.value!!.latitude,
+ viewModel.origin.value!!.longitude))
+ .title("Marker in Origin")
+ .icon(BitmapDescriptorFactory.fromBitmap(
+ ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_flag_circle_origin_36)))
+ .anchor(0.5F,0.5F))
+
+ val marker = map.addMarker(
+ MarkerOptions()
+ .position(latLng)
+ .title("Marker in Dest")
+ .snippet(snippet)
+ .draggable(true)
+ .icon(BitmapDescriptorFactory.fromBitmap(
+ ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_flag_circle_dest_36)))
+ .anchor(0.5F,0.5F)
+ )
+
+ if (marker != null) {
+ viewModel.setDest(marker.position)
+ }
+ }
+ }
+
+
+ //マーカーをドラッグ時に、マーカーのLatLngを更新
+ private fun setOnMarkerDrag(map: GoogleMap) {
+ map.setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener {
+ private var start: com.google.maps.model.LatLng? = null
+ private var end: com.google.maps.model.LatLng? = null
+
+ override fun onMarkerDragStart(marker: Marker) {
+ marker.position.let { start =
+ com.google.maps.model.LatLng(it.latitude, it.longitude)
+ }
+ }
+
+ override fun onMarkerDrag(marker: Marker) {
+ // Do Nothing.
+ }
+
+ override fun onMarkerDragEnd(marker: Marker) {
+ marker.position.let { end =
+ com.google.maps.model.LatLng(it.latitude, it.longitude)
+ }
+ viewModel.setDest(marker.position)
+ }
+ })
+ }
+
+ //Polylineを更新
+ private fun updatePolyline(directionsResult: DirectionsResult?, googleMap: GoogleMap?) {
+ googleMap ?: return
+ directionsResult ?: return
+ removePolyline()
+ addPolyline(directionsResult, googleMap)
+ }
+
+ // 線を消す.
+ private fun removePolyline() {
+ if (map != null && polyline != null) {
+ polyline?.remove()
+ }
+ }
+
+ // 線を引く
+ private fun addPolyline(directionsResult: DirectionsResult, map: GoogleMap) {
+ val polylineOptions = PolylineOptions()
+ polylineOptions.width(POLYLINE_WIDTH)
+ // ARGB32bit形式.
+ polylineOptions.color(R.color.map_polyline_stroke)
+ val decodedPath = PolyUtil.decode(directionsResult.routes[0].overviewPolyline.encodedPath)
+ polyline = map.addPolyline(polylineOptions.addAll(decodedPath))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/dest/AddTrialDestViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/dest/AddTrialDestViewModel.kt
new file mode 100644
index 0000000..670ae21
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/dest/AddTrialDestViewModel.kt
@@ -0,0 +1,62 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.dest
+
+import android.app.Application
+import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import com.google.android.gms.maps.model.LatLng
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.DirectionsApiHelper
+import kotlinx.coroutines.launch
+
+class AddTrialDestViewModel(application: Application) : AndroidViewModel(application) {
+ private val _directionsResult = MutableLiveData()
+ val directionsResult: LiveData = _directionsResult
+
+ private val _origin = MutableLiveData()
+ val origin: LiveData get() = _origin
+
+ private val _dest = MutableLiveData()
+ val dest: LiveData get() = _dest
+
+ private val _navFrag = MutableLiveData()
+ val navFrag: LiveData get() = _navFrag
+
+ fun setOrigin(latLng: LatLng) {
+ _origin.value = latLng
+ }
+
+ fun setDest(latLng: LatLng) {
+ Log.i("DestViewModel", "setDest:${latLng.toString()}")
+ _dest.value = latLng
+ directionApiExecute()
+ }
+
+ fun removeDest() {
+ if (_dest != null) {
+// _dest.value = null
+ }
+ }
+
+ fun navStart() {
+ _navFrag.value = true
+ }
+
+ fun navCompleted() {
+ _navFrag.value = false
+ }
+
+ //DirectionAPIを実行
+ fun directionApiExecute() {
+ viewModelScope.launch {
+ val result = DirectionsApiHelper().onlyOriginDestExecute(
+ com.google.maps.model.LatLng(_origin.value!!.latitude, _origin.value!!.longitude),
+ com.google.maps.model.LatLng(_dest.value!!.latitude, _dest.value!!.longitude)
+ )
+ Log.i("DestViewModel", "result:${result.toString()}")
+ _directionsResult.value = result
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/origin/AddTrialOriginFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/origin/AddTrialOriginFragment.kt
new file mode 100644
index 0000000..894c1d5
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/origin/AddTrialOriginFragment.kt
@@ -0,0 +1,197 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.origin
+
+import android.app.AlertDialog
+import android.content.DialogInterface
+import android.content.pm.PackageManager
+import android.location.Location
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import com.google.android.gms.location.FusedLocationProviderClient
+import com.google.android.gms.location.LocationServices
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.BitmapDescriptorFactory
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.Marker
+import com.google.android.gms.maps.model.MarkerOptions
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentAddTrialOriginBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.util.ConverterVectorToBitmap
+import java.util.*
+
+class AddTrialOriginFragment : Fragment() {
+
+ companion object {
+ private const val ZOOM_SIZE = 14f
+ }
+ private val REQUEST_LOCATION_PERMISSION = 1
+
+ private var map: GoogleMap? = null
+ private lateinit var viewModel: AddTrialOriginViewModel
+
+ private lateinit var _binding: FragmentAddTrialOriginBinding
+ private val binding get() = _binding
+
+ private lateinit var fusedLocationClient: FusedLocationProviderClient
+ private var currentPosition: LatLng? = null
+
+ private val callback = OnMapReadyCallback { googleMap ->
+ map = googleMap
+ enableMyLocation()
+ setMapLongClick(googleMap)
+ setOnMarkerDrag(googleMap)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ _binding = FragmentAddTrialOriginBinding.inflate(inflater, container, false)
+ viewModel = ViewModelProvider(this).get(AddTrialOriginViewModel::class.java)
+ binding.nextButton.setOnClickListener {
+ if (viewModel.origin.value != null) {
+ viewModel.navStart()
+ }
+ }
+
+ val builder = AlertDialog.Builder(requireContext())
+ builder.setTitle("トライアルを作成").setMessage("スタート地点を設定")
+ .setPositiveButton("ok",null)
+ builder.show()
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
+ mapFragment?.getMapAsync(callback)
+ observeLiveData()
+ }
+
+ private fun observeLiveData() {
+ viewModel.navFrag.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+ if (it == true) {
+ Log.i("originValue", viewModel.origin.value.toString())
+ val action =
+ AddTrialOriginFragmentDirections.actionNavigationAddTrialOriginToNavigationAddTrialDest(
+ LatLng(
+ viewModel.origin.value!!.latitude,
+ viewModel.origin.value!!.longitude
+ )
+ )
+ this.findNavController().navigate(action)
+ viewModel.navCompleted()
+ }
+ })
+ }
+
+ private fun isPermissionGranted() : Boolean {
+ return ContextCompat.checkSelfPermission(
+ requireContext(),
+ android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
+ }
+
+ private fun enableMyLocation() {
+ if (isPermissionGranted()) {
+ map!!.isMyLocationEnabled = true
+
+ fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity())
+ fusedLocationClient.lastLocation
+ .addOnSuccessListener { location : Location? ->
+ currentPosition = LatLng(location!!.latitude,location.longitude)
+ Log.i("HomeFragment","FusedLocationClient:${location.latitude.toString()}")
+ map?.apply {
+ Log.i("HomeFragment","currentPosition:${currentPosition.toString()}")
+ moveCamera(CameraUpdateFactory.newLatLngZoom(
+ currentPosition!!, 14f
+ ))
+// LatLng(26.40005132585051, 127.74633288655508)
+ }
+ }
+ }
+ else {
+ ActivityCompat.requestPermissions(
+ this.requireActivity(),
+ arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
+ REQUEST_LOCATION_PERMISSION
+ )
+ }
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == REQUEST_LOCATION_PERMISSION) {
+ if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
+ enableMyLocation()
+ }
+ }
+ }
+
+ //マップをロングクリック時にマーカーを追加
+ private fun setMapLongClick(map: GoogleMap) {
+ map.setOnMapLongClickListener{latLng ->
+ val snippet = String.format(
+ Locale.getDefault(),
+ "Lat: %1$.5f, Long: %2$.5f",
+ latLng.latitude,
+ latLng.longitude
+ )
+ //マップをクリア
+ map.clear()
+
+ val marker = map.addMarker(
+ MarkerOptions()
+ .position(latLng)
+ .title("Marker in Dest")
+ .snippet(snippet)
+ .draggable(true)
+ .icon(BitmapDescriptorFactory.fromBitmap(ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_flag_circle_origin_36)))
+ .anchor(0.5F,0.5F)
+ )
+
+ if (marker != null) {
+ viewModel.setOrigin(marker.position)
+ }
+ }
+ }
+
+ //マーカーをドラッグ時に、マーカーのLatLngを更新
+ private fun setOnMarkerDrag(map: GoogleMap) {
+ map.setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener {
+ private var start: com.google.maps.model.LatLng? = null
+ private var end: com.google.maps.model.LatLng? = null
+
+ override fun onMarkerDragStart(marker: Marker) {
+ marker.position.let { start =
+ com.google.maps.model.LatLng(it.latitude, it.longitude)
+ }
+ }
+
+ override fun onMarkerDrag(marker: Marker) {
+ // Do Nothing.
+ }
+
+ override fun onMarkerDragEnd(marker: Marker) {
+ marker.position.let { end =
+ com.google.maps.model.LatLng(it.latitude, it.longitude)
+ }
+ viewModel.setOrigin(marker.position)
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/origin/AddTrialOriginViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/origin/AddTrialOriginViewModel.kt
new file mode 100644
index 0000000..af518fb
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/origin/AddTrialOriginViewModel.kt
@@ -0,0 +1,33 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.origin
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.google.android.gms.maps.model.LatLng
+
+class AddTrialOriginViewModel(application: Application) : AndroidViewModel(application) {
+ private val _origin = MutableLiveData()
+ val origin: LiveData get() = _origin
+
+ private val _navFrag = MutableLiveData()
+ val navFrag: LiveData get() = _navFrag
+
+ fun setOrigin(latLng: LatLng) {
+ _origin.value = latLng
+ }
+
+ fun removeOrigin() {
+ if (_origin != null) {
+// _origin.value = null
+ }
+ }
+
+ fun navStart() {
+ _navFrag.value = true
+ }
+
+ fun navCompleted() {
+ _navFrag.value = false
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/start/AddTrialFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/start/AddTrialFragment.kt
new file mode 100644
index 0000000..a008764
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/start/AddTrialFragment.kt
@@ -0,0 +1,66 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.start
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentAddTrialBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.CreatedTrialAdapter
+
+class AddTrialFragment : Fragment() {
+
+ private lateinit var binding: FragmentAddTrialBinding
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ val viewModel =
+ ViewModelProvider(this).get(AddTrialViewModel::class.java)
+ binding = FragmentAddTrialBinding.inflate(layoutInflater)
+
+ viewModel.getTrialList("testUserID")
+
+ val adapter = CreatedTrialAdapter(binding.createdTrialList.context)
+ binding.createdTrialList.adapter = adapter
+
+ val dividerItemDecoration = DividerItemDecoration(
+ requireContext(), LinearLayoutManager(requireContext()).getOrientation())
+ binding.createdTrialList.addItemDecoration(dividerItemDecoration)
+
+ //RecyclerViewのclickListener
+ adapter.setOnItemClickListener { view, position ->
+ val action = AddTrialFragmentDirections.actionNavigationCreateTrialToTrialDetailFragment(
+ viewModel.testData.value!!.get(position).id,false
+ )
+ this.findNavController().navigate(action)
+ }
+
+ viewModel.testData.observe(viewLifecycleOwner, Observer{
+ it?.let {
+ adapter.submitList(it)
+ }
+ })
+
+ //トライアルの作成開始
+ viewModel.navFrag.observe(viewLifecycleOwner, Observer {
+ if (it == true) {
+ this.findNavController().navigate(
+ AddTrialFragmentDirections.actionNavigationAddTrialToNavigationAddTrialOrigin()
+ )
+ viewModel.navCompleted()
+ }
+ })
+
+ binding.startButton.setOnClickListener { viewModel.navStart() }
+
+ return binding.root
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/start/AddTrialViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/start/AddTrialViewModel.kt
new file mode 100644
index 0000000..965b4dd
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/start/AddTrialViewModel.kt
@@ -0,0 +1,49 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.start
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Trial
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.TrialRepositoryDummy
+import kotlinx.coroutines.launch
+
+class AddTrialViewModel : ViewModel() {
+ private val trialRepositoryDummy = TrialRepositoryDummy()
+
+ private val _testData : MutableLiveData> = MutableLiveData(listOf())
+ val testData: LiveData> get() = _testData
+
+ private val _navFrag = MutableLiveData()
+ val navFrag: LiveData get() = _navFrag
+
+ private val _collectState = MutableLiveData()
+ val collectState: LiveData get() = _collectState
+
+ fun navStart() {
+ _navFrag.value = true
+ }
+
+ fun navCompleted() {
+ _navFrag.value = null
+ }
+
+ //リポジトリからテストデータを持ってくる
+ fun getTrialList(userId: String) {
+ viewModelScope.launch {
+ trialRepositoryDummy.getTriedTrialByUserId(userId).collect{
+ when(it) {
+ is Result.Loading -> _collectState.value = "Loading"
+ is Result.Success -> {
+ _collectState.value = "Success"
+ _testData.value = it.data!!
+ Log.i("getTrialList","testData:${it}")
+ }
+ is Result.Error -> _collectState.value = "Error"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/waypoints/AddTrialMapsFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/waypoints/AddTrialMapsFragment.kt
new file mode 100644
index 0000000..e1e920c
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/waypoints/AddTrialMapsFragment.kt
@@ -0,0 +1,247 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.waypoints
+
+import android.app.AlertDialog
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.widget.AppCompatEditText
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.*
+import com.google.maps.android.PolyUtil
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentAddTrialMapsBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.util.ConverterVectorToBitmap
+import java.util.*
+
+class AddTrialMapsFragment : Fragment() {
+ companion object {
+ private const val ZOOM_SIZE = 14f
+ private const val POLYLINE_WIDTH = 12f
+ }
+
+ private var map: GoogleMap? = null
+ private var polyline: Polyline? = null
+ private val overview = 0
+ private lateinit var viewModel: AddTrialMapsViewModel
+
+ private lateinit var _binding: FragmentAddTrialMapsBinding
+
+ // This property is only valid between onCreateView and
+ // onDestroyView.
+ private val binding get() = _binding
+
+ private val callback = OnMapReadyCallback { googleMap ->
+ map = googleMap
+ viewModel.directionApiExecute()
+ moveCamera()
+ setMapLongClick(googleMap)
+ setMarkerClick(googleMap)
+ setOnMarkerDrag(googleMap)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ _binding = FragmentAddTrialMapsBinding.inflate(inflater, container, false)
+ viewModel = ViewModelProvider(this).get(AddTrialMapsViewModel::class.java)
+ val args = AddTrialMapsFragmentArgs.fromBundle(
+ requireArguments()
+ )
+ viewModel.setOrigin(args.originLatLng)
+ viewModel.setDest(args.destLatLng)
+
+ val builder = AlertDialog.Builder(requireContext())
+ builder.setTitle("トライアルを作成").setMessage("中継地点を設定")
+ .setPositiveButton("ok",null)
+ builder.show()
+
+ val dialogLayout = LayoutInflater.from(requireContext()).inflate(R.layout.trial_name_edit_dialog, null)
+ val editText = dialogLayout.findViewById(R.id.editTextDialog)
+
+ val dialog = AlertDialog.Builder(requireContext())
+ .setTitle("トライアル名の設定")
+ .setMessage("トライアル名を入力してください。")
+ .setView(dialogLayout)
+ .setPositiveButton("OK") { dialog, _ ->
+ // OKボタンを押したときの処理
+ viewModel.setTrialName(editText.text.toString())
+ viewModel.createNewTrial()
+ dialog.dismiss()
+ }
+ .setNegativeButton("キャンセル") { dialog, _ ->
+ // キャンセルボタンを押したときの処理
+
+ dialog.dismiss()
+ }
+ .create()
+
+ // AppCompatEditTextにTextChangedListenerをセット
+ editText.addTextChangedListener( object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
+
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
+
+ override fun afterTextChanged(s: Editable?) {
+ // 1~32文字の時だけOKボタンを有効化する
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled =
+ !(s.isNullOrEmpty() || s.length > 16)
+ }
+ })
+
+ binding.saveButton.setOnClickListener {
+ dialog.show()
+ }
+
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
+ mapFragment?.getMapAsync(callback)
+ observeLiveData()
+ }
+
+ private fun observeLiveData() {
+ viewModel.directionsResult.observe(viewLifecycleOwner, androidx.lifecycle.Observer{
+ updatePolyline(it, map)
+ })
+
+ viewModel.navFrag.observe(viewLifecycleOwner, Observer {
+ if (it) {
+ val action =
+ AddTrialMapsFragmentDirections.actionNavigationAddTrialMapsToNavigationAddTrial()
+ this.findNavController().navigate(action)
+ viewModel.navCompleted()
+ }
+ })
+ }
+
+ //カメラを移動
+ private fun moveCamera() {
+ // Add a marker in Sydney and move the camera
+ val origin = LatLng(viewModel.origin.value!!.latitude, viewModel.origin.value!!.longitude)
+ val dest = LatLng(viewModel.dest.value!!.latitude, viewModel.dest.value!!.longitude)
+ map?.apply {
+ addMarker(MarkerOptions().position(origin).title("Marker in Origin")
+ .icon(BitmapDescriptorFactory.fromBitmap(
+ ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_flag_circle_origin_36)))
+ .anchor(0.5F,0.5F))
+ addMarker(MarkerOptions().position(dest).title("Marker in Dest")
+ .icon(BitmapDescriptorFactory.fromBitmap(
+ ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_flag_circle_dest_36)))
+ .anchor(0.5F,0.5F))
+ moveCamera(CameraUpdateFactory.newLatLngZoom(origin, ZOOM_SIZE))
+ }
+ }
+
+ //マップをロングクリック時にマーカーを追加
+ private fun setMapLongClick(map: GoogleMap) {
+ map.setOnMapLongClickListener{latLng ->
+ val snippet = String.format(
+ Locale.getDefault(),
+ "Lat: %1$.5f, Long: %2$.5f",
+ latLng.latitude,
+ latLng.longitude
+ )
+
+ val marker = map.addMarker(
+ MarkerOptions()
+ .position(latLng)
+ .title("drop")
+ .snippet(snippet)
+ .draggable(true)
+ .icon(BitmapDescriptorFactory.fromBitmap(ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_waypoints_circle_36)))
+ .anchor(0.5F,0.5F)
+ )
+
+
+ Log.i("MapsActivity", "doAddMarker")
+ if (marker != null) {
+ viewModel.addWaypointMarker(marker)
+ }
+ Log.i("MapsActivity", "didAddMarker")
+ }
+ }
+
+ //マーカーをクリック時にそのマーカーを削除
+ private fun setMarkerClick(map: GoogleMap) {
+ map.setOnMarkerClickListener{marker ->
+ if(marker.title != "Marker in Origin") {
+ if (marker.title != "Marker in Dest") {
+ viewModel.removeWaypointMarker(marker)
+ marker.remove()
+ }
+ }
+ return@setOnMarkerClickListener true
+ }
+ }
+
+ //マーカーをドラッグ時に、マーカーのLatLngを更新
+ private fun setOnMarkerDrag(map: GoogleMap) {
+ map.setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener {
+ private var start: com.google.maps.model.LatLng? = null
+ private var end: com.google.maps.model.LatLng? = null
+
+ override fun onMarkerDragStart(marker: Marker) {
+ marker.position.let { start =
+ com.google.maps.model.LatLng(it.latitude, it.longitude)
+ }
+ }
+
+ override fun onMarkerDrag(marker: Marker) {
+ // Do Nothing.
+ }
+
+ override fun onMarkerDragEnd(marker: Marker) {
+ marker.position.let { end =
+ com.google.maps.model.LatLng(it.latitude, it.longitude)
+ }
+ viewModel.changeWaypointMarker(marker)
+ }
+ })
+ }
+
+ //Polylineを更新
+ private fun updatePolyline(directionsResult: DirectionsResult?, googleMap: GoogleMap?) {
+ googleMap ?: return
+ directionsResult ?: return
+ removePolyline()
+ addPolyline(directionsResult, googleMap)
+ }
+
+ // 線を消す.
+ private fun removePolyline() {
+ if (map != null && polyline != null) {
+ polyline?.remove()
+ }
+ }
+
+ // 線を引く
+ private fun addPolyline(directionsResult: DirectionsResult, map: GoogleMap) {
+ val polylineOptions = PolylineOptions()
+ polylineOptions.width(POLYLINE_WIDTH)
+ // ARGB32bit形式.
+ polylineOptions.color(R.color.map_polyline_stroke)
+ val decodedPath =
+ PolyUtil.decode(directionsResult.routes[overview].overviewPolyline.encodedPath)
+ polyline = map.addPolyline(polylineOptions.addAll(decodedPath))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/waypoints/AddTrialMapsViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/waypoints/AddTrialMapsViewModel.kt
new file mode 100644
index 0000000..1e58c67
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/add_trial/waypoints/AddTrialMapsViewModel.kt
@@ -0,0 +1,147 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.waypoints
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.Marker
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Trial
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.TrialRepositoryDummy
+import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.DirectionsApiHelper
+import kotlinx.coroutines.launch
+
+class AddTrialMapsViewModel(application: Application) : AndroidViewModel(application) {
+ private val _directionsResult = MutableLiveData()
+ val directionsResult: LiveData = _directionsResult
+
+ private val trialRepositoryDummy = TrialRepositoryDummy()
+
+ private val _navFrag = MutableLiveData()
+ val navFrag: LiveData get() = _navFrag
+
+ private val _origin = MutableLiveData()
+ val origin: LiveData get() = _origin
+
+ private val _dest = MutableLiveData()
+ val dest: LiveData get() = _dest
+
+ private val _waypointMarkers = MutableLiveData>().apply {
+ value = ArrayList()
+ }
+ val waypointMarkers: LiveData> get() = _waypointMarkers
+
+ private val _trialCourse = MutableLiveData>().apply {
+ value = ArrayList()
+ }
+ val trialCourse: LiveData> get() = _trialCourse
+
+ private val _trialName = MutableLiveData()
+ val trialName: LiveData get() = _trialName
+
+ fun setTrialName(name: String) {
+ _trialName.value = name
+ }
+
+ fun setOrigin(latLng: LatLng) {
+ _origin.value = latLng
+ }
+
+ fun setDest(latLng: LatLng) {
+ _dest.value = latLng
+ }
+
+ //waypointを追加する
+ fun addWaypointMarker(marker: Marker) {
+ _waypointMarkers.value?.add(marker)
+ directionApiExecute()
+ }
+
+ //waypointを削除する
+ fun removeWaypointMarker(marker: Marker) {
+ _waypointMarkers.value?.remove(marker)
+ directionApiExecute()
+ }
+
+ //waypointの値を変更する(ドラッグ&ドロップ)
+ fun changeWaypointMarker(marker: Marker) {
+ val markersId = ArrayList()
+ for (id in _waypointMarkers.value!!) {
+ markersId.add(id.id)
+ }
+ val index = markersId.indexOf(marker.id)
+ _waypointMarkers.value?.set(index,marker)
+ directionApiExecute()
+ }
+
+ //Marker型のwaypointsをDirectionAPIにリクエストを送る用のString型に変更する
+ private fun markersToString(): String {
+ val sb = StringBuilder()
+ if (_waypointMarkers != null) {
+ for (waypoint in _waypointMarkers.value!!) {
+// sb.append(waypoint.lat.toString() + "," + waypoint.lng.toString() + "|")
+ sb.append(waypoint.position.latitude.toString() + "," + waypoint.position.longitude.toString() + "|")
+ }
+ }
+ return sb.toString()
+ }
+
+
+ //DirectionAPIを実行
+ fun directionApiExecute() {
+ viewModelScope.launch {
+ if (_waypointMarkers.value!!.isNotEmpty()) {
+ val waypointsString = markersToString()
+ val result = DirectionsApiHelper().execute(
+ com.google.maps.model.LatLng(_origin.value!!.latitude, _origin.value!!.longitude),
+ com.google.maps.model.LatLng(_dest.value!!.latitude, _dest.value!!.longitude),
+ waypointsString
+ )
+ _directionsResult.value = result
+ }else {
+ val result = DirectionsApiHelper().onlyOriginDestExecute(
+ com.google.maps.model.LatLng(_origin.value!!.latitude, _origin.value!!.longitude),
+ com.google.maps.model.LatLng(_dest.value!!.latitude, _dest.value!!.longitude),
+ )
+ _directionsResult.value = result
+ }
+
+ }
+ }
+
+ fun createNewTrial() {
+ _trialCourse.value!!.add(_origin.value!!)
+ for (waypoint in _waypointMarkers.value!!) {
+ _trialCourse.value!!.add(LatLng(waypoint.position.latitude,waypoint.position.longitude))
+ }
+ _trialCourse.value!!.add(_dest.value!!)
+ val trial = Trial.Marathon(_trialName.value!!,
+ "ひじかた",
+ _trialCourse.value!!.toList()[0],
+ _trialCourse.value!!.toList(),
+ "2022年10月16日")
+ viewModelScope.launch {
+ trialRepositoryDummy.createTrial(trial).collect{
+ when(it) {
+ is Result.Loading -> {
+
+ }
+ is Result.Success -> {
+ //navigationを実装
+ _navFrag.value = true
+ }
+ is Result.Error -> {
+
+ }
+ }
+ }
+ }
+ }
+
+ fun navCompleted() {
+ _navFrag.value = false
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/CheckRecordFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/CheckRecordFragment.kt
deleted file mode 100644
index 30f508f..0000000
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/CheckRecordFragment.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentCheckRecordBinding
-
-class CheckRecordFragment : Fragment() {
-
- private var _binding: FragmentCheckRecordBinding? = null
-
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- val notificationsViewModel =
- ViewModelProvider(this).get(CheckRecordViewModel::class.java)
-
- _binding = FragmentCheckRecordBinding.inflate(inflater, container, false)
- val root: View = binding.root
-
- val textView: TextView = binding.textCheckRecord
- notificationsViewModel.text.observe(viewLifecycleOwner) {
- textView.text = it
- }
- return root
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/CheckRecordViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/CheckRecordViewModel.kt
deleted file mode 100644
index dcce1ff..0000000
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/CheckRecordViewModel.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-
-class CheckRecordViewModel : ViewModel() {
-
- private val _text = MutableLiveData().apply {
- value = "This is CheckRecord Fragment"
- }
- val text: LiveData = _text
-}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/RecordNavGraphFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/RecordNavGraphFragment.kt
new file mode 100644
index 0000000..15f72ca
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/RecordNavGraphFragment.kt
@@ -0,0 +1,25 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.navigation.fragment.NavHostFragment
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentCheckRecordListBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentCreateTrialBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentRecordNavGraphBinding
+
+class RecordNavGraphFragment : Fragment() {
+ private lateinit var binding: FragmentRecordNavGraphBinding
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = FragmentRecordNavGraphBinding.inflate(layoutInflater)
+ val navHostFragment = childFragmentManager.findFragmentById(R.id.nav_host_check_record) as NavHostFragment
+ val navController = navHostFragment.navController
+ return binding.root
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_detail/RecordDetailFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_detail/RecordDetailFragment.kt
new file mode 100644
index 0000000..9635ceb
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_detail/RecordDetailFragment.kt
@@ -0,0 +1,138 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_detail
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.MarkerOptions
+import com.google.android.gms.maps.model.Polyline
+import com.google.android.gms.maps.model.PolylineOptions
+import com.google.maps.android.PolyUtil
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentRecordDetailBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_detail.RecordDetailFragmentArgs
+import jp.ac.okinawa_ct.nitoc_ict.aroa.util.TimeFormat
+
+class RecordDetailFragment : Fragment() {
+
+ companion object {
+ private const val ZOOM_SIZE = 16f
+ private const val POLYLINE_WIDTH = 12f
+ }
+
+ private var _binding: FragmentRecordDetailBinding? = null
+ private val binding get() = _binding!!
+
+ private lateinit var viewModel: RecordDetailViewModel
+
+ private var map: GoogleMap? = null
+ private var polyline: Polyline? = null
+
+ private lateinit var args: RecordDetailFragmentArgs
+
+ private val callback = OnMapReadyCallback { googleMap ->
+ map = googleMap
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ _binding = FragmentRecordDetailBinding.inflate(layoutInflater)
+ viewModel = ViewModelProvider(this).get(RecordDetailViewModel::class.java)
+ args = RecordDetailFragmentArgs.fromBundle(requireArguments())
+
+ viewModel.setTrialId(args.trialId)
+ viewModel.getTrialById()
+ viewModel.setRecordId(args.recordId)
+ viewModel.getRecordById()
+
+ binding.checkRankingButton.setOnClickListener {
+ viewModel.navStart()
+ }
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
+ mapFragment?.getMapAsync(callback)
+ observeLiveData()
+ }
+
+ private fun observeLiveData() {
+ viewModel.record.observe(viewLifecycleOwner, Observer {
+ viewModel.assignmentRecordDate()
+ binding.recordTime.text = TimeFormat().convertLongToTimeString(viewModel.recordTime.value!!)
+
+ })
+
+ viewModel.trial.observe(viewLifecycleOwner, Observer {
+ viewModel.assignmentTrialData()
+ map?.moveCamera(
+ CameraUpdateFactory.newLatLngZoom((viewModel.trial.value!!.position), ZOOM_SIZE)
+ )
+ })
+
+ viewModel.trialCourse.observe(viewLifecycleOwner, Observer {
+ viewModel.courseTranslate()
+ viewModel.directionApiExecute()
+ map?.addMarker(MarkerOptions().position(viewModel.origin.value!!).title("origin"))
+ map?.addMarker(MarkerOptions().position(viewModel.dest.value!!).title("dest"))
+ })
+
+ viewModel.directionsResult.observe(viewLifecycleOwner, Observer{
+ updatePolyline(it, map)
+ viewModel.getDistance()
+ binding.recordDistance.text = viewModel.trialDistance.value.toString() + "m"
+ val speed = viewModel.trialDistance.value!! / viewModel.recordTime.value!! * 3.6
+ binding.recordSpeed.text = speed.toString() + "km/h"
+ })
+
+ viewModel.navFrag.observe(viewLifecycleOwner, Observer {
+ if (it == true) {
+ val action = RecordDetailFragmentDirections.actionRecordDetailFragmentToRecordRankingFragment(
+ args.trialId
+ )
+ this.findNavController().navigate(action)
+ viewModel.navCompleted()
+ }
+ })
+ }
+
+ //Polylineを更新
+ private fun updatePolyline(directionsResult: DirectionsResult?, googleMap: GoogleMap?) {
+ googleMap ?: return
+ directionsResult ?: return
+ removePolyline()
+ addPolyline(directionsResult, googleMap)
+ }
+
+ // 線を消す.
+ private fun removePolyline() {
+ if (map != null && polyline != null) {
+ polyline?.remove()
+ }
+ }
+
+ // 線を引く
+ private fun addPolyline(directionsResult: DirectionsResult, map: GoogleMap) {
+ val polylineOptions = PolylineOptions()
+ polylineOptions.width(POLYLINE_WIDTH)
+ // ARGB32bit形式.
+ polylineOptions.color(R.color.map_polyline_stroke)
+ val decodedPath =
+ PolyUtil.decode(directionsResult.routes[0].overviewPolyline.encodedPath)
+ polyline = map.addPolyline(polylineOptions.addAll(decodedPath))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_detail/RecordDetailViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_detail/RecordDetailViewModel.kt
new file mode 100644
index 0000000..d738538
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_detail/RecordDetailViewModel.kt
@@ -0,0 +1,173 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_detail
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.google.android.gms.maps.model.LatLng
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Record
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Trial
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.RecordRepositoryDummy
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.TrialRepositoryDummy
+import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.DirectionsApiHelper
+import kotlinx.coroutines.launch
+
+class RecordDetailViewModel : ViewModel() {
+ private val trialRepositoryDummy = TrialRepositoryDummy()
+ private val recordRepositoryDummy = RecordRepositoryDummy()
+
+ private val _navFrag = MutableLiveData()
+ val navFrag: LiveData get() = _navFrag
+
+ fun navStart() {
+ _navFrag.value = true
+ }
+
+ fun navCompleted() {
+ _navFrag.value = false
+ //LiveDataの初期化を行う
+ }
+
+ private val _directionsResult = MutableLiveData()
+ val directionsResult: LiveData = _directionsResult
+
+ private val _origin = MutableLiveData()
+ val origin: LiveData get() = _origin
+
+ private val _dest = MutableLiveData()
+ val dest: LiveData get() = _dest
+
+ private val _waypoints = MutableLiveData>()
+ val waypoints: LiveData> get() = _waypoints
+
+ private val _recordId = MutableLiveData()
+ val recordId: LiveData get() = _recordId
+
+ private val _record = MutableLiveData()
+ val record: LiveData get() = _record
+
+ private val _recordTime = MutableLiveData()
+ val recordTime: LiveData get() = _recordTime
+
+ private val _trial = MutableLiveData()
+ val trial: LiveData get() = _trial
+
+ private val _trialId = MutableLiveData()
+ val trialId: LiveData get() = _trialId
+
+ private val _trialCourse = MutableLiveData>()
+ val trialCourse: LiveData> get() = _trialCourse
+
+ private val _trialDistance = MutableLiveData().apply {
+ value = 0
+ }
+ val trialDistance: LiveData get() = _trialDistance
+
+ fun setTrialId(id: String) {
+ _trialId.value = id
+ }
+
+ fun setRecordId(id: String) {
+ _recordId.value = id
+ }
+
+ fun getTrialById() {
+ viewModelScope.launch {
+ trialRepositoryDummy.getTrialById(_trialId.value!!).collect{
+ when(it) {
+ is Result.Loading -> "Loading"
+ is Result.Success -> {
+ _trial.value = it.data!!
+ }
+ is Result.Error -> "Error"
+ }
+ }
+ }
+ }
+
+ fun getRecordById() {
+ viewModelScope.launch {
+ recordRepositoryDummy.getRecordByTrialIdAndRecordId(trialId.value!!, _recordId.value!!).collect{
+ when(it) {
+ is Result.Loading -> "Loading"
+ is Result.Success -> {
+ _record.value = it.data!!
+ }
+ is Result.Error -> "Error"
+ }
+ }
+ }
+ }
+
+ fun assignmentTrialData() {
+ _trial.value?.let {
+ when(it) {
+ is Trial.Marathon -> {
+ _trialCourse.value = it.course
+ }
+ else -> {}
+ }
+ }
+ }
+
+ fun assignmentRecordDate() {
+ _record.value?.let {
+ when(it) {
+ is Record.MarathonRecord -> {
+ _recordTime.value = it.time
+ }
+ else -> {}
+ }
+ }
+ }
+
+ fun getDistance() {
+ _trialDistance.value = 0L
+ for (route in _directionsResult.value!!.routes) {
+ for (leg in route.legs) {
+ _trialDistance.value = _trialDistance.value?.plus(leg.distance.inMeters)
+ }
+ }
+ }
+
+ fun courseTranslate() {
+ _trialCourse.value?.let { courselatLng ->
+ _origin.value = courselatLng.first()
+ _dest.value = courselatLng.last()
+ _waypoints.value = ArrayList()
+ for (latLng in courselatLng) {
+ when(latLng) {
+ courselatLng.first() -> continue
+ courselatLng.last() -> continue
+ else -> _waypoints.value?.add(latLng)
+ }
+ }
+ }
+ }
+
+ private fun latLngToString(): String {
+ val sb = StringBuilder()
+ if (_waypoints != null) {
+ for (waypoint in _waypoints.value!!) {
+ sb.append(waypoint.latitude.toString() + "," + waypoint.longitude.toString() + "|")
+ }
+ }
+ return sb.toString()
+ }
+
+ fun directionApiExecute() {
+ viewModelScope.launch {
+ val waypointsString = latLngToString()
+ val result = DirectionsApiHelper().execute(
+ com.google.maps.model.LatLng(_origin.value!!.latitude, _origin.value!!.longitude),
+ com.google.maps.model.LatLng(_dest.value!!.latitude, _dest.value!!.longitude),
+ waypointsString
+ )
+ _directionsResult.value = result
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/CheckRecordListFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/CheckRecordListFragment.kt
new file mode 100644
index 0000000..76f2f50
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/CheckRecordListFragment.kt
@@ -0,0 +1,55 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_list
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentCheckRecordListBinding
+
+class CheckRecordListFragment : Fragment() {
+
+ private var _binding: FragmentCheckRecordListBinding? = null
+
+ // This property is only valid between onCreateView and
+ // onDestroyView.
+ private val binding get() = _binding!!
+ private lateinit var viewModel: CheckRecordListViewModel
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ viewModel =
+ ViewModelProvider(this).get(CheckRecordListViewModel::class.java)
+
+ _binding = FragmentCheckRecordListBinding.inflate(inflater, container, false)
+
+ val adapter = RecordListAdapter(requireContext())
+ binding.recordList.adapter = adapter
+ viewModel.testRecordList.observe(viewLifecycleOwner, Observer {
+ adapter.submitList(it)
+ })
+
+ val dividerItemDecoration = DividerItemDecoration(
+ requireContext(), LinearLayoutManager(requireContext()).getOrientation())
+ binding.recordList.addItemDecoration(dividerItemDecoration)
+
+ adapter.setOnItemClickListener { view, position ->
+ val action = CheckRecordListFragmentDirections
+ .actionCheckRecordListFragmentToRecordDetailFragment(
+ viewModel.testRecordList.value!!.get(position).recordId,
+ viewModel.testRecordList.value!!.get(position).trialId
+ )
+ this.findNavController().navigate(action)
+ }
+
+ return binding.root
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/CheckRecordListViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/CheckRecordListViewModel.kt
new file mode 100644
index 0000000..2d7f75d
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/CheckRecordListViewModel.kt
@@ -0,0 +1,39 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_list
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Record
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.RecordRepositoryDummy
+import kotlinx.coroutines.launch
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result as Result
+
+class CheckRecordListViewModel : ViewModel() {
+ private val recordRepositoryDummy = RecordRepositoryDummy()
+
+ private val _testRecordList = MutableLiveData>()
+ val testRecordList: LiveData> get() = _testRecordList
+
+ private val _collectState = MutableLiveData()
+ val collectState: LiveData get() = _collectState
+
+ init {
+ getRecordList()
+ }
+
+ private fun getRecordList() {
+ viewModelScope.launch {
+ recordRepositoryDummy.getMyRecords("").collect{
+ when(it) {
+ is Result.Loading -> _collectState.value = "Loading"
+ is Result.Success -> {
+ _testRecordList.value = it.data!!
+ }
+ is Result.Error -> _collectState.value = "Error"
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/RecordListAdapter.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/RecordListAdapter.kt
new file mode 100644
index 0000000..0fdb9f8
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_list/RecordListAdapter.kt
@@ -0,0 +1,66 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_list
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Record
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.ListItemRecordBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.util.TimeFormat
+
+typealias OnItemClickListener = (view: View, position: Int) -> Unit
+
+class RecordListAdapter(
+ context: Context
+) : ListAdapter(ITEM_CALLBACK) {
+ private val inflater = LayoutInflater.from(context)
+
+ private var onItemClickListener: OnItemClickListener? = null
+
+ class BindingHolder(
+ val binding: ListItemRecordBinding
+ ) : RecyclerView.ViewHolder(binding.root)
+ companion object {
+ val ITEM_CALLBACK = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: Record,
+ newItem: Record
+ ): Boolean = oldItem.userId == newItem.userId
+
+ override fun areContentsTheSame(
+ oldItem: Record,
+ newItem: Record
+ ): Boolean = oldItem == newItem
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder {
+ val binding = ListItemRecordBinding.inflate(inflater, parent, false)
+ return BindingHolder(binding)
+ }
+
+ override fun onBindViewHolder(bindingHolder: BindingHolder, position: Int) {
+ val current = getItem(position)
+ when(current) {
+ is Record.MarathonRecord -> {
+ bindingHolder.binding.recordTrialDay.text = current.date
+ bindingHolder.binding.recordTrialName.text = current.trialName
+ bindingHolder.binding.recordTrialDistance.text = current.distance.toString() + "m"
+ bindingHolder.binding.recordTrialTime.text = TimeFormat().convertLongToTimeString(current.time)
+ bindingHolder.binding.recordTrialSpeed.text = (current.distance / current.time * 3.6).toString() + "km/h"
+ }
+ else -> {}
+ }
+
+ bindingHolder.binding.root.setOnClickListener {
+ onItemClickListener?.invoke(it,position)
+ }
+ }
+
+ fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
+ this.onItemClickListener = onItemClickListener
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingFragment.kt
new file mode 100644
index 0000000..f4c7a6f
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingFragment.kt
@@ -0,0 +1,49 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_ranking
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentRecordRankingBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_ranking.RecordRankingFragmentArgs
+
+class RecordRankingFragment : Fragment() {
+ private var _biding: FragmentRecordRankingBinding? = null
+ private val binding get() = _biding!!
+ private lateinit var viewModel: RecordRankingViewModel
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ _biding = FragmentRecordRankingBinding.inflate(layoutInflater)
+ viewModel = ViewModelProvider(this).get(RecordRankingViewModel::class.java)
+
+ val args = RecordRankingFragmentArgs.fromBundle(requireArguments())
+ viewModel.setTrialId(args.trialId)
+
+ viewModel.trialId.observe(viewLifecycleOwner, Observer {
+ viewModel.getRanking(it)
+ })
+
+ val adapter = RecordRankingListAdapter(requireContext())
+ binding.rankingList.adapter = adapter
+
+ val dividerItemDecoration = DividerItemDecoration(
+ requireContext(), LinearLayoutManager(requireContext()).getOrientation())
+ binding.rankingList.addItemDecoration(dividerItemDecoration)
+
+ viewModel.testRecordData.observe(viewLifecycleOwner, Observer {
+ adapter.submitList(it)
+ })
+
+
+ return binding.root
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingListAdapter.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingListAdapter.kt
new file mode 100644
index 0000000..a6594e3
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingListAdapter.kt
@@ -0,0 +1,60 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_ranking
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Record
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.ListItemRecordRankingBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.util.TimeFormat
+
+typealias OnItemClickListener = (view: View, position: Int) -> Unit
+
+class RecordRankingListAdapter(
+ context: Context
+) : ListAdapter(ITEM_CALLBACK) {
+ private val inflater = LayoutInflater.from(context)
+
+ private var onItemClickListener: OnItemClickListener? = null
+
+ class BindingHolder(
+ val binding: ListItemRecordRankingBinding
+ ) : RecyclerView.ViewHolder(binding.root)
+ companion object {
+ val ITEM_CALLBACK = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: Record,
+ newItem: Record
+ ): Boolean = oldItem.userId == newItem.userId
+
+ override fun areContentsTheSame(
+ oldItem: Record,
+ newItem: Record
+ ): Boolean = oldItem == newItem
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder {
+ val binding = ListItemRecordRankingBinding.inflate(inflater, parent, false)
+ return BindingHolder(binding)
+ }
+
+ override fun onBindViewHolder(bindingHolder: BindingHolder, position: Int) {
+ val current = getItem(position)
+ when(current) {
+ is Record.MarathonRecord -> {
+ bindingHolder.binding.rankNum.text = current.rank.toString()
+ bindingHolder.binding.userName.text = current.userId
+ bindingHolder.binding.time.text = TimeFormat().convertLongToTimeString(current.time)
+ }
+ else -> {}
+ }
+ }
+
+ fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
+ this.onItemClickListener = onItemClickListener
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingViewModel.kt
new file mode 100644
index 0000000..a22bca7
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/check_record/record_ranking/RecordRankingViewModel.kt
@@ -0,0 +1,38 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.check_record.record_ranking
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Record
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.RecordRepositoryDummy
+import kotlinx.coroutines.launch
+
+class RecordRankingViewModel : ViewModel() {
+ private val recordRepositoryDummy = RecordRepositoryDummy()
+
+ private val _testRecordData = MutableLiveData>()
+ val testRecordData: LiveData> get() = _testRecordData
+
+ private val _trialId = MutableLiveData()
+ val trialId: LiveData get() = _trialId
+
+ fun setTrialId(id: String) {
+ _trialId.value = id
+ }
+
+ fun getRanking(trialId: String) {
+ viewModelScope.launch {
+ recordRepositoryDummy.getRecords(trialId,1,10).collect{
+ when(it) {
+ is Result.Loading -> {}
+ is Result.Success -> {
+ _testRecordData.value = it.data!!
+ }
+ is Result.Error -> {}
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/create_trial/CreateTrialFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/create_trial/CreateTrialFragment.kt
new file mode 100644
index 0000000..c5d49c0
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/create_trial/CreateTrialFragment.kt
@@ -0,0 +1,32 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.create_trial
+
+import androidx.lifecycle.ViewModelProvider
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.navigation.fragment.NavHostFragment
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentAddTrialBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentCreateTrialBinding
+
+class CreateTrialFragment : Fragment() {
+
+ companion object {
+ fun newInstance() = CreateTrialFragment()
+ }
+
+ private lateinit var viewModel: CreateTrialViewModel
+ private lateinit var binding: FragmentCreateTrialBinding
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentCreateTrialBinding.inflate(layoutInflater)
+ val navHostFragment = childFragmentManager.findFragmentById(R.id.nav_host_create_trial) as NavHostFragment
+ val navController = navHostFragment.navController
+ return binding.root
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/create_trial/CreateTrialViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/create_trial/CreateTrialViewModel.kt
new file mode 100644
index 0000000..f460df1
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/create_trial/CreateTrialViewModel.kt
@@ -0,0 +1,7 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.create_trial
+
+import androidx.lifecycle.ViewModel
+
+class CreateTrialViewModel : ViewModel() {
+ // TODO: Implement the ViewModel
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/detail/TrialDetailFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/detail/TrialDetailFragment.kt
new file mode 100644
index 0000000..0efa7d4
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/detail/TrialDetailFragment.kt
@@ -0,0 +1,132 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.detail
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.MarkerOptions
+import com.google.android.gms.maps.model.Polyline
+import com.google.android.gms.maps.model.PolylineOptions
+import com.google.maps.android.PolyUtil
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentTrialDetailBinding
+
+class TrialDetailFragment : Fragment() {
+ companion object {
+ private const val ZOOM_SIZE = 14f
+ private const val POLYLINE_WIDTH = 12f
+ }
+
+ private var map: GoogleMap? = null
+ private var polyline: Polyline? = null
+ private lateinit var viewModel: TrialDetailViewModel
+
+ private lateinit var _binding: FragmentTrialDetailBinding
+ private val binding get() = _binding
+
+ private lateinit var args: TrialDetailFragmentArgs
+
+ private val callback = OnMapReadyCallback { googleMap ->
+ map = googleMap
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentTrialDetailBinding.inflate(layoutInflater)
+ viewModel = ViewModelProvider(this).get(TrialDetailViewModel::class.java)
+ args = TrialDetailFragmentArgs.fromBundle(requireArguments())
+ if (!args.canStartTrial) {
+ binding.startTrialButton.visibility = View.INVISIBLE
+ }else {
+ binding.startTrialButton.setOnClickListener {
+ //トライアルに参加
+ }
+ }
+ binding.checkRankingButton.setOnClickListener {
+ viewModel.navStart()
+ }
+ viewModel.setTrialId(args.trialId)
+ viewModel.getTrialById()
+
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
+ mapFragment?.getMapAsync(callback)
+ observeLiveData()
+ }
+
+ private fun observeLiveData() {
+ viewModel.trial.observe(viewLifecycleOwner, Observer {
+ viewModel.assignmentTrialData()
+ map?.moveCamera(
+ CameraUpdateFactory.newLatLngZoom(viewModel.trial.value!!.position, ZOOM_SIZE))
+ binding.detailTrialName.text = viewModel.trial.value!!.name
+ binding.detailTrialAuthorUserId.text = viewModel.trial.value!!.authorUserId
+ binding.detailTrialPosition.text = viewModel.trialPosition.value.toString()
+ })
+
+ viewModel.trialCourse.observe(viewLifecycleOwner, Observer {
+ viewModel.courseTranslate()
+ viewModel.directionApiExecute()
+ map?.addMarker(MarkerOptions().position(viewModel.origin.value!!).title("origin"))
+ map?.addMarker(MarkerOptions().position(viewModel.dest.value!!).title("dest"))
+ })
+
+ viewModel.directionsResult.observe(viewLifecycleOwner, Observer{
+ updatePolyline(it, map)
+ viewModel.getDistance()
+ binding.detailTrialDistance.text = viewModel.trialDistance.value.toString() + "m"
+ })
+
+ viewModel.navFrag.observe(viewLifecycleOwner, Observer {
+ if (it == true) {
+ val action = TrialDetailFragmentDirections
+ .actionTrialDetailFragmentToRecordRankingFragment(args.trialId)
+ this.findNavController().navigate(action)
+ viewModel.navCompleted()
+ }
+ })
+ }
+
+ //Polylineを更新
+ private fun updatePolyline(directionsResult: DirectionsResult?, googleMap: GoogleMap?) {
+ googleMap ?: return
+ directionsResult ?: return
+ removePolyline()
+ addPolyline(directionsResult, googleMap)
+ }
+
+ // 線を消す.
+ private fun removePolyline() {
+ if (map != null && polyline != null) {
+ polyline?.remove()
+ }
+ }
+
+ // 線を引く
+ private fun addPolyline(directionsResult: DirectionsResult, map: GoogleMap) {
+ val polylineOptions = PolylineOptions()
+ polylineOptions.width(POLYLINE_WIDTH)
+ // ARGB32bit形式.
+ polylineOptions.color(R.color.map_polyline_stroke)
+ val decodedPath =
+ PolyUtil.decode(directionsResult.routes[0].overviewPolyline.encodedPath)
+ polyline = map.addPolyline(polylineOptions.addAll(decodedPath))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/detail/TrialDetailViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/detail/TrialDetailViewModel.kt
new file mode 100644
index 0000000..b76952b
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/detail/TrialDetailViewModel.kt
@@ -0,0 +1,136 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.detail
+
+import android.app.Application
+import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import com.google.android.gms.maps.model.LatLng
+import com.google.maps.model.DirectionsResult
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Trial
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.TrialRepositoryDummy
+import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.add_trial.DirectionsApiHelper
+import kotlinx.coroutines.launch
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result as Result
+
+class TrialDetailViewModel(application: Application) : AndroidViewModel(application) {
+ private val trialRepositoryDummy = TrialRepositoryDummy()
+
+ private val _navFrag = MutableLiveData()
+ val navFrag: LiveData get() = _navFrag
+
+ fun navStart() {
+ _navFrag.value = true
+ }
+
+ fun navCompleted() {
+ _navFrag.value = false
+ //LiveDataの初期化を行う
+ }
+
+ private val _directionsResult = MutableLiveData()
+ val directionsResult: LiveData = _directionsResult
+
+ private val _origin = MutableLiveData()
+ val origin: LiveData get() = _origin
+
+ private val _dest = MutableLiveData()
+ val dest: LiveData get() = _dest
+
+ private val _waypoints = MutableLiveData>()
+ val waypoints: LiveData> get() = _waypoints
+
+ private val _trial = MutableLiveData()
+ val trial: LiveData get() = _trial
+
+ private val _trialId = MutableLiveData()
+ val trialId: LiveData get() = _trialId
+
+ private val _trialPosition = MutableLiveData()
+ val trialPosition: LiveData get() = _trialPosition
+
+ private val _trialCourse = MutableLiveData>()
+ val trialCourse: LiveData> get() = _trialCourse
+
+ private val _trialDistance = MutableLiveData().apply {
+ value = 0
+ }
+ val trialDistance: LiveData get() = _trialDistance
+
+ fun setTrialId(id: String) {
+ _trialId.value = id
+ }
+
+ fun getTrialById() {
+ viewModelScope.launch {
+ trialRepositoryDummy.getTrialById(_trialId.value!!).collect{
+ when(it) {
+ is Result.Loading -> {}
+ is Result.Success -> {
+ _trial.value = it.data!!
+ }
+ is Result.Error -> {}
+ }
+ }
+ }
+ }
+
+ fun assignmentTrialData() {
+ _trial.value?.let {
+ when(it) {
+ is Trial.Marathon -> {
+ _trialPosition.value = it.position
+ _trialCourse.value = it.course
+ }
+ else -> {}
+ }
+ }
+ }
+
+ fun getDistance() {
+ _trialDistance.value = 0L
+ for (route in _directionsResult.value!!.routes) {
+ for (leg in route.legs) {
+ _trialDistance.value = _trialDistance.value?.plus(leg.distance.inMeters)
+ }
+ }
+ }
+
+ fun courseTranslate() {
+ _trialCourse.value?.let { courselatLngs ->
+ _origin.value = courselatLngs.first()
+ _dest.value = courselatLngs.last()
+ _waypoints.value = ArrayList()
+ for (latLng in courselatLngs) {
+ when(latLng) {
+ courselatLngs.first() -> continue
+ courselatLngs.last() -> continue
+ else -> _waypoints.value?.add(latLng)
+ }
+ }
+ }
+ }
+
+ private fun latLngToString(): String {
+ val sb = StringBuilder()
+ if (_waypoints != null) {
+ for (waypoint in _waypoints.value!!) {
+ sb.append(waypoint.latitude.toString() + "," + waypoint.longitude.toString() + "|")
+ }
+ }
+ return sb.toString()
+ }
+
+ fun directionApiExecute() {
+ viewModelScope.launch {
+ val waypointsString = latLngToString()
+ val result = DirectionsApiHelper().execute(
+ com.google.maps.model.LatLng(_origin.value!!.latitude, _origin.value!!.longitude),
+ com.google.maps.model.LatLng(_dest.value!!.latitude, _dest.value!!.longitude),
+ waypointsString
+ )
+ _directionsResult.value = result
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeFragment.kt
index 1cda398..0288211 100644
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeFragment.kt
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeFragment.kt
@@ -1,49 +1,144 @@
package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.home
+import android.content.pm.PackageManager
+import android.location.Location
import android.os.Bundle
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.TextView
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import com.google.android.gms.location.FusedLocationProviderClient
+import com.google.android.gms.location.LocationServices
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.BitmapDescriptorFactory
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.MarkerOptions
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentHomeBinding
-import jp.ac.okinawa_ct.nitoc_ict.aroa.ui.trial_detail.TrialDetailActivity
+import jp.ac.okinawa_ct.nitoc_ict.aroa.util.ConverterVectorToBitmap
+
class HomeFragment : Fragment() {
+ private val REQUEST_LOCATION_PERMISSION = 1
private var _binding: FragmentHomeBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
private val binding get() = _binding!!
+ private lateinit var map : GoogleMap
+ private lateinit var homeViewModel: HomeViewModel
+
+ private lateinit var fusedLocationClient: FusedLocationProviderClient
+ private var currentPosition: LatLng? = null
+
+
+ private val callback = OnMapReadyCallback { googleMap ->
+ map = googleMap
+ enableMyLocation()
+ setMarkerClick(googleMap)
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- val homeViewModel =
- ViewModelProvider(this)[HomeViewModel::class.java]
-
_binding = FragmentHomeBinding.inflate(inflater, container, false)
- val root: View = binding.root
+ homeViewModel =
+ ViewModelProvider(this).get(HomeViewModel::class.java)
+
- val textView: TextView = binding.textHome
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
+ mapFragment.getMapAsync(callback)
+ observeLiveData()
+ }
- textView.setOnClickListener {
- val intent = TrialDetailActivity.makeIntent(requireContext(), "TrialId")
- startActivity(intent)
+ private fun observeLiveData() {
+ homeViewModel.foundTrials.observe(viewLifecycleOwner) {
+ for (data in it){
+ map.addMarker(MarkerOptions()
+ .position(data.position)
+ .title(data.id)
+ .icon(
+ BitmapDescriptorFactory.fromBitmap(
+ ConverterVectorToBitmap().getBitmapFromVectorDrawable(
+ requireContext(),R.drawable.ic_baseline_trial_circle_36)))
+ .anchor(0.5F,0.5F))
+ }
}
+ }
+
+ private fun setMarkerClick(map: GoogleMap) {
+ homeViewModel.foundTrials.observe(viewLifecycleOwner) {
+ map.setOnMarkerClickListener{marker ->
+ marker.title?.let {
+ val action = HomeFragmentDirections.actionHomeFragmentToTrialDetailFragment(
+ it,true
+ )
+ this.findNavController().navigate(action)
+ }
+ return@setOnMarkerClickListener true
+ }
+ }
+ }
+
+ private fun isPermissionGranted() : Boolean {
+ return ContextCompat.checkSelfPermission(
+ requireContext(),
+ android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
+ }
+
+ private fun enableMyLocation() {
+ if (isPermissionGranted()) {
+ map.isMyLocationEnabled = true
- homeViewModel.text.observe(viewLifecycleOwner) {
- textView.text = it
+ fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity())
+ fusedLocationClient.lastLocation
+ .addOnSuccessListener { location : Location? ->
+ currentPosition = LatLng(location!!.latitude,location.longitude)
+ Log.i("HomeFragment","FusedLocationClient:${location.latitude.toString()}")
+ map.apply {
+ Log.i("HomeFragment","currentPosition:${currentPosition.toString()}")
+ moveCamera(CameraUpdateFactory.newLatLngZoom(
+ currentPosition!!, 16f
+ ))
+// LatLng(26.526703736324663, 128.03039187339328)
+ binding.progressBar.visibility = View.GONE
+ }
+ }
+ }
+ else {
+ ActivityCompat.requestPermissions(
+ this.requireActivity(),
+ arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
+ REQUEST_LOCATION_PERMISSION
+ )
}
- return root
}
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == REQUEST_LOCATION_PERMISSION) {
+ if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
+ enableMyLocation()
+ }
+ }
}
+
}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeNavGraphFragment.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeNavGraphFragment.kt
new file mode 100644
index 0000000..26b1bdf
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeNavGraphFragment.kt
@@ -0,0 +1,25 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.home
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.navigation.fragment.NavHostFragment
+import jp.ac.okinawa_ct.nitoc_ict.aroa.R
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentCheckRecordListBinding
+import jp.ac.okinawa_ct.nitoc_ict.aroa.databinding.FragmentHomeNavGraphBinding
+
+class HomeNavGraphFragment : Fragment() {
+ private lateinit var binding: FragmentHomeNavGraphBinding
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = FragmentHomeNavGraphBinding.inflate(layoutInflater)
+ val navHostFragment = childFragmentManager.findFragmentById(R.id.nav_host_home_trial) as NavHostFragment
+ val navController = navHostFragment.navController
+ return binding.root
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeViewModel.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeViewModel.kt
index 523c1d9..943b684 100644
--- a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeViewModel.kt
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/ui/home/HomeViewModel.kt
@@ -3,11 +3,41 @@ package jp.ac.okinawa_ct.nitoc_ict.aroa.ui.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.google.android.gms.maps.model.LatLng
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Result
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.dto.Trial
+import jp.ac.okinawa_ct.nitoc_ict.aroa.data.repository.TrialRepositoryDummy
+import kotlinx.coroutines.launch
class HomeViewModel : ViewModel() {
+ private val trialRepository = TrialRepositoryDummy()
- private val _text = MutableLiveData().apply {
- value = "This is home Fragment"
+ private val _foundTrials: MutableLiveData> = MutableLiveData(listOf())
+ val foundTrials: LiveData> = _foundTrials
+
+ init {
+ findTrialsNearMe()
+ }
+
+ fun findTrialsNearMe() {
+
+ viewModelScope.launch {
+
+ trialRepository
+ .getTrialsNear(LatLng(26.526230, 128.030372), 100.0)
+ .collect {
+ when (it) {
+ is Result.Loading -> _foundTrials.value = listOf()
+ is Result.Success -> {
+ _foundTrials.value = it.data!!
+ }
+
+ is Result.Error -> {
+ _foundTrials.value = listOf()
+ }
+ }
+ }
+ }
}
- val text: LiveData = _text
}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/util/ConverterVectorToBitmap.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/util/ConverterVectorToBitmap.kt
new file mode 100644
index 0000000..d9269b7
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/util/ConverterVectorToBitmap.kt
@@ -0,0 +1,20 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.util
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import androidx.core.content.ContextCompat
+
+class ConverterVectorToBitmap {
+ fun getBitmapFromVectorDrawable(context: Context, drawableId: Int): Bitmap {
+ val drawable = ContextCompat.getDrawable(context, drawableId)
+ val bitmap = Bitmap.createBitmap(
+ drawable!!.intrinsicWidth,
+ drawable.intrinsicHeight, Bitmap.Config.ARGB_8888
+ )
+ val canvas = Canvas(bitmap)
+ drawable.setBounds(0, 0, canvas.width, canvas.height)
+ drawable.draw(canvas)
+ return bitmap
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/util/TimeFormat.kt b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/util/TimeFormat.kt
new file mode 100644
index 0000000..a97941f
--- /dev/null
+++ b/app/src/main/java/jp/ac/okinawa_ct/nitoc_ict/aroa/util/TimeFormat.kt
@@ -0,0 +1,17 @@
+package jp.ac.okinawa_ct.nitoc_ict.aroa.util
+
+import android.annotation.SuppressLint
+import android.text.format.DateUtils
+
+class TimeFormat {
+ @SuppressLint("SimpleDateFormat")
+ fun convertLongToTimeString(time: Long): String {
+// val hours = time / 3600
+// val minutes = time % 3600 / 60
+// val seconds = time % 3600 % 60
+// val formatTime = hours.toString() + ":" + minutes.toString() + ":" + seconds.toString()
+ return DateUtils.formatElapsedTime(time)
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_baseline_flag_circle_dest_36.xml b/app/src/main/res/drawable/ic_baseline_flag_circle_dest_36.xml
new file mode 100644
index 0000000..3af23e4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_flag_circle_dest_36.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_flag_circle_origin_36.xml b/app/src/main/res/drawable/ic_baseline_flag_circle_origin_36.xml
new file mode 100644
index 0000000..aefbb1a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_flag_circle_origin_36.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_trial_circle_36.xml b/app/src/main/res/drawable/ic_baseline_trial_circle_36.xml
new file mode 100644
index 0000000..a34b66b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_trial_circle_36.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_waypoints_circle_36.xml b/app/src/main/res/drawable/ic_baseline_waypoints_circle_36.xml
new file mode 100644
index 0000000..7d2fef9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_waypoints_circle_36.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/under_line.xml b/app/src/main/res/drawable/under_line.xml
new file mode 100644
index 0000000..f088712
--- /dev/null
+++ b/app/src/main/res/drawable/under_line.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index a488693..39d13e9 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,11 +1,9 @@
+ android:layout_height="match_parent">
+ tools:context=".ui.addtrial.start.AddTrialFragment">
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_add_trial_dest.xml b/app/src/main/res/layout/fragment_add_trial_dest.xml
new file mode 100644
index 0000000..1a1f85e
--- /dev/null
+++ b/app/src/main/res/layout/fragment_add_trial_dest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_add_trial_maps.xml b/app/src/main/res/layout/fragment_add_trial_maps.xml
new file mode 100644
index 0000000..2bb5cf6
--- /dev/null
+++ b/app/src/main/res/layout/fragment_add_trial_maps.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_add_trial_origin.xml b/app/src/main/res/layout/fragment_add_trial_origin.xml
new file mode 100644
index 0000000..673ac1c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_add_trial_origin.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_check_record_list.xml b/app/src/main/res/layout/fragment_check_record_list.xml
new file mode 100644
index 0000000..fc9f620
--- /dev/null
+++ b/app/src/main/res/layout/fragment_check_record_list.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_create_trial.xml b/app/src/main/res/layout/fragment_create_trial.xml
new file mode 100644
index 0000000..020dd47
--- /dev/null
+++ b/app/src/main/res/layout/fragment_create_trial.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 5c0a701..02ae69e 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -1,19 +1,24 @@
-
-
+
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home_nav_graph.xml b/app/src/main/res/layout/fragment_home_nav_graph.xml
new file mode 100644
index 0000000..4ca8e8b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_home_nav_graph.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_record_detail.xml b/app/src/main/res/layout/fragment_record_detail.xml
new file mode 100644
index 0000000..6aa943f
--- /dev/null
+++ b/app/src/main/res/layout/fragment_record_detail.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_record_nav_graph.xml b/app/src/main/res/layout/fragment_record_nav_graph.xml
new file mode 100644
index 0000000..f40c942
--- /dev/null
+++ b/app/src/main/res/layout/fragment_record_nav_graph.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_record_ranking.xml b/app/src/main/res/layout/fragment_record_ranking.xml
new file mode 100644
index 0000000..413ebce
--- /dev/null
+++ b/app/src/main/res/layout/fragment_record_ranking.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_trial_detail.xml b/app/src/main/res/layout/fragment_trial_detail.xml
new file mode 100644
index 0000000..e7ddf90
--- /dev/null
+++ b/app/src/main/res/layout/fragment_trial_detail.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_record.xml b/app/src/main/res/layout/list_item_record.xml
new file mode 100644
index 0000000..ad85e13
--- /dev/null
+++ b/app/src/main/res/layout/list_item_record.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_record_ranking.xml b/app/src/main/res/layout/list_item_record_ranking.xml
new file mode 100644
index 0000000..26d5847
--- /dev/null
+++ b/app/src/main/res/layout/list_item_record_ranking.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_trial.xml b/app/src/main/res/layout/list_item_trial.xml
new file mode 100644
index 0000000..b888bb3
--- /dev/null
+++ b/app/src/main/res/layout/list_item_trial.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_check_record.xml b/app/src/main/res/layout/trial_name_edit_dialog.xml
similarity index 58%
rename from app/src/main/res/layout/fragment_check_record.xml
rename to app/src/main/res/layout/trial_name_edit_dialog.xml
index 91eabf3..49a9d74 100644
--- a/app/src/main/res/layout/fragment_check_record.xml
+++ b/app/src/main/res/layout/trial_name_edit_dialog.xml
@@ -1,16 +1,19 @@
+ android:layout_height="wrap_content">
-
diff --git a/app/src/main/res/navigation/bottom_nav_navigation.xml b/app/src/main/res/navigation/bottom_nav_navigation.xml
index edc06d5..1fe3c26 100644
--- a/app/src/main/res/navigation/bottom_nav_navigation.xml
+++ b/app/src/main/res/navigation/bottom_nav_navigation.xml
@@ -7,19 +7,19 @@
+ tools:layout="@layout/fragment_check_record_list" />
\ No newline at end of file
diff --git a/app/src/main/res/navigation/check_record_navigation.xml b/app/src/main/res/navigation/check_record_navigation.xml
new file mode 100644
index 0000000..ca2801d
--- /dev/null
+++ b/app/src/main/res/navigation/check_record_navigation.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/create_trial_navigation.xml b/app/src/main/res/navigation/create_trial_navigation.xml
new file mode 100644
index 0000000..0fdc87a
--- /dev/null
+++ b/app/src/main/res/navigation/create_trial_navigation.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/home_trial_navigation.xml b/app/src/main/res/navigation/home_trial_navigation.xml
new file mode 100644
index 0000000..f50c9a3
--- /dev/null
+++ b/app/src/main/res/navigation/home_trial_navigation.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 3ea99c2..e17f156 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -2,7 +2,6 @@
#FFF3821A
#40000000
-
#FFBB86FC
#FF6200EE
#FF3700B3
@@ -10,4 +9,6 @@
#FF018786
#FF000000
#FFFFFFFF
+ #777777
+ #F3821A
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index cf7f259..7c44337 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,14 +4,15 @@ buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.3.13'
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
- classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.2"
+ classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0"
}
}
plugins {
- id 'com.android.application' version '7.2.2' apply false
- id 'com.android.library' version '7.2.2' apply false
+ id 'com.android.application' version '7.3.0' apply false
+ id 'com.android.library' version '7.3.0' apply false
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
+ id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' apply false
}
task clean(type: Delete) {
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index b8010e9..dda5dfd 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Tue Aug 23 02:20:20 JST 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME