diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..7ce6325 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 89935b5..0897082 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,10 +1,17 @@ + diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..fdf8d99 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index c2b3ddc..8978d23 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,6 @@ - - + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 03b0703..882371f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,7 +3,6 @@ plugins { alias(libs.plugins.jetbrainsKotlinAndroid) id("com.google.gms.google-services") } - android { namespace = "com.example.chiecnonkydieu" compileSdk = 34 @@ -34,6 +33,10 @@ android { kotlinOptions { jvmTarget = "1.8" } + + buildFeatures { + viewBinding = true + } } dependencies { @@ -47,4 +50,11 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) + + //coroutine + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0") + + //wheel + implementation("androidx.navigation:navigation-dynamic-features-fragment:2.7.7") + implementation ("com.github.thanhniencung:LuckyWheel:a6110f5128") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 53c2086..270e0e3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,22 @@ android:supportsRtl="true" android:theme="@style/Theme.ChiecNonKyDieu" tools:targetApi="31"> + + + + + @@ -21,6 +37,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/MainActivity.kt b/app/src/main/java/com/example/chiecnonkydieu/MainActivity.kt index 7488fa7..3dabaea 100644 --- a/app/src/main/java/com/example/chiecnonkydieu/MainActivity.kt +++ b/app/src/main/java/com/example/chiecnonkydieu/MainActivity.kt @@ -1,29 +1,60 @@ package com.example.chiecnonkydieu +import android.content.Intent import android.os.Bundle import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat -import com.google.firebase.Firebase -import com.google.firebase.database.database +import com.example.chiecnonkydieu.databinding.ActivityMainBinding +import com.example.chiecnonkydieu.ui.CreateRoomActivity +import com.example.chiecnonkydieu.ui.PlayingRoomActivity +import com.example.chiecnonkydieu.ui.SearchRoomActivity +import com.example.chiecnonkydieu.ui.wheel.WheelActivity class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() - setContentView(R.layout.activity_main) + binding = ActivityMainBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } - // Write a message to the database - val database = Firebase.database - val myRef = database.getReference("message") +// // Write a message to the database +// val database = Firebase.database +// val myRef = database.getReference("message") +// +// myRef.setValue("Hello, World!") +// +// val intent = Intent(this, WaitingRoomActivity::class.java) +// startActivity(intent) + binding.btnBatDau.setOnClickListener { +// goToPlayingRoom() + val intent = Intent(this, WheelActivity::class.java) + startActivity(intent) + } - myRef.setValue("Hello, World!") + binding.btnTaoPhong.setOnClickListener { + val intent = Intent(this, CreateRoomActivity::class.java) + startActivity(intent) + } + binding.btnTimPhong.setOnClickListener { + val intent = Intent(this, SearchRoomActivity::class.java) + startActivity(intent) + } + + } + private fun goToPlayingRoom() { + // TODO Set cung + val intent = Intent(this, PlayingRoomActivity::class.java) + intent.putExtra("room_id", "7232") + startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/data/DataSource.kt b/app/src/main/java/com/example/chiecnonkydieu/data/DataSource.kt new file mode 100644 index 0000000..59545de --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/data/DataSource.kt @@ -0,0 +1,5 @@ +package com.example.chiecnonkydieu.data + +import rubikstudio.library.model.LuckyItem + + diff --git a/app/src/main/java/com/example/chiecnonkydieu/data/GameData.kt b/app/src/main/java/com/example/chiecnonkydieu/data/GameData.kt new file mode 100644 index 0000000..4374aa6 --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/data/GameData.kt @@ -0,0 +1,93 @@ +package com.example.chiecnonkydieu.data + +import android.content.Context +import android.util.Log +import android.widget.Toast +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.google.firebase.Firebase +import com.google.firebase.database.DataSnapshot +import com.google.firebase.database.DatabaseError +import com.google.firebase.database.DatabaseReference +import com.google.firebase.database.ValueEventListener +import com.google.firebase.database.database +import kotlinx.coroutines.CompletableDeferred +import kotlin.coroutines.coroutineContext + +object GameData { + private var _gameModel: MutableLiveData = MutableLiveData() + val gameModel: LiveData = _gameModel + + const val REFERENCE_ROOM = "rooms" + private lateinit var appContext: Context + + + val database: DatabaseReference = Firebase.database.reference + + fun initialize(context: Context) { + + appContext = context.applicationContext + } + fun saveGameModel(model: GameModel) { + _gameModel.postValue(model) + database.child(REFERENCE_ROOM).child(model.gameId.toString()).setValue(model) + } + + suspend fun joinOnlineGame(player: Player, gameId: Int): Boolean { + val deferred = CompletableDeferred() + + database.child(REFERENCE_ROOM).child(gameId.toString()) + .get() + .addOnSuccessListener { snapshot -> + val gameModel: GameModel? = snapshot.getValue(GameModel::class.java) + if (gameModel != null) { + when (gameModel.playersList.size) { + 1 -> { + gameModel.playersList.add(player) + gameModel.gameStatus = GameStatus.JOINED1 + saveGameModel(gameModel) + Toast.makeText(appContext, "Successfully joined1 game", Toast.LENGTH_LONG).show() + deferred.complete(true) + } + 2 -> { + gameModel.playersList.add(player) + gameModel.gameStatus = GameStatus.JOINED2 + saveGameModel(gameModel) + Toast.makeText(appContext, "Successfully joined2 game", Toast.LENGTH_LONG).show() + deferred.complete(true) + } + else -> { + Toast.makeText(appContext, "Game is full (3 players)", Toast.LENGTH_LONG).show() + deferred.complete(false) + } + } + } else { + Toast.makeText(appContext, "Cannot find room with id $gameId", Toast.LENGTH_LONG).show() + deferred.complete(false) + } + } + .addOnFailureListener { exception -> + Toast.makeText(appContext, "Error: $exception", Toast.LENGTH_LONG).show() + deferred.complete(false) + } + + return deferred.await() + } + + suspend fun fetchGameModel(gameId: Int) { + database.child(REFERENCE_ROOM).child(gameId.toString()) + .addValueEventListener(object : ValueEventListener { + override fun onDataChange(snapshot: DataSnapshot) { + val gameModel: GameModel? = snapshot.getValue(GameModel::class.java) + if (gameModel != null) { + saveGameModel(gameModel) + } + } + + override fun onCancelled(error: DatabaseError) { + // Handle error + Log.e("fetchGameModel", "Error fetching game model: ${error.message}") + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/data/GameModel.kt b/app/src/main/java/com/example/chiecnonkydieu/data/GameModel.kt new file mode 100644 index 0000000..52200b7 --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/data/GameModel.kt @@ -0,0 +1,23 @@ +package com.example.chiecnonkydieu.data + +import android.health.connect.datatypes.units.Length + +data class GameModel( + val gameId: Int = -1, + val winner: String = "", + var gameStatus: GameStatus = GameStatus.CREATED, + val playersList: MutableList = mutableListOf(), + val currentPlayer: Player = Player(), + val currentQuestion: String = "", + val currentAnswer: String = "HA NOI", + val currentGuess: String = " A N " + +) + +enum class GameStatus { + CREATED, + JOINED1, + JOINED2, + INPROGRESS, + FINISHED +} diff --git a/app/src/main/java/com/example/chiecnonkydieu/data/Player.kt b/app/src/main/java/com/example/chiecnonkydieu/data/Player.kt new file mode 100644 index 0000000..0565137 --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/data/Player.kt @@ -0,0 +1,7 @@ +package com.example.chiecnonkydieu.data + +data class Player( + val name: String = "Player", + val gender: Boolean = true, + val score: Int = 0 +) diff --git a/app/src/main/java/com/example/chiecnonkydieu/ui/CreateRoomActivity.kt b/app/src/main/java/com/example/chiecnonkydieu/ui/CreateRoomActivity.kt new file mode 100644 index 0000000..d914deb --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/ui/CreateRoomActivity.kt @@ -0,0 +1,70 @@ +package com.example.chiecnonkydieu.ui + +import android.content.Intent +import android.os.Bundle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.lifecycle.lifecycleScope +import com.example.chiecnonkydieu.R +import com.example.chiecnonkydieu.data.GameData +import com.example.chiecnonkydieu.data.GameModel +import com.example.chiecnonkydieu.data.GameStatus +import com.example.chiecnonkydieu.data.Player +import com.example.chiecnonkydieu.databinding.ActivityCreateRoomBinding +import kotlinx.coroutines.launch +import kotlin.random.Random + +class CreateRoomActivity : AppCompatActivity() { + private lateinit var binding: ActivityCreateRoomBinding + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityCreateRoomBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.create_room_main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + + val toolbar: Toolbar = binding.toolbar + setSupportActionBar(toolbar) + + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setDisplayShowHomeEnabled(true) + + + binding.tvMaPhong.text = (1000 .. 9999).random().toString() + binding.btnCreateRoom.setOnClickListener { + lifecycleScope.launch { + GameData.initialize(applicationContext) + val gameModel: GameModel = GameModel( + gameStatus = GameStatus.CREATED, + gameId = binding.tvMaPhong.text.toString().toInt(), + currentQuestion = "Thủ đô của Việt Nam nằm ở đâu?" + ) + gameModel.playersList.add(Player(binding.edtName.text.toString())) + GameData.saveGameModel( + gameModel + ) + } + goToWaitingRooom() + } + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + + fun goToWaitingRooom() { + val intent = Intent(this, WaitingRoomActivity::class.java) + intent.putExtra("room_id", binding.tvMaPhong.text.toString()) + startActivity(intent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/ui/PlayingRoomActivity.kt b/app/src/main/java/com/example/chiecnonkydieu/ui/PlayingRoomActivity.kt new file mode 100644 index 0000000..876f2fc --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/ui/PlayingRoomActivity.kt @@ -0,0 +1,186 @@ +package com.example.chiecnonkydieu.ui + +import android.content.DialogInterface +import android.content.Intent +import android.os.Bundle +import android.text.InputType +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.EditText +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.core.content.ContentProviderCompat.requireContext +import androidx.core.content.ContextCompat +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope +import com.example.chiecnonkydieu.R +import com.example.chiecnonkydieu.data.GameData +import com.example.chiecnonkydieu.data.GameModel +import com.example.chiecnonkydieu.data.GameStatus +import com.example.chiecnonkydieu.databinding.ActivityPlayingRoomBinding +import com.example.chiecnonkydieu.ui.wheel.WheelActivity +import com.example.chiecnonkydieu.ui.wheel.WheelViewModel +import kotlinx.coroutines.launch +import rubikstudio.library.LuckyWheelView + + +class PlayingRoomActivity : AppCompatActivity() { + private lateinit var binding: ActivityPlayingRoomBinding + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + + binding = ActivityPlayingRoomBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + + + val toolbar: Toolbar = binding.toolbar + setSupportActionBar(toolbar) + + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setDisplayShowHomeEnabled(true) + + + lifecycleScope.launch { + GameData.fetchGameModel(intent.getStringExtra("room_id").toString().toInt()) + + } + + GameData.gameModel.observe(this, Observer { gameModel -> + updateUi(gameModel) + }) + + binding.btnDoan.setOnClickListener { + Toast.makeText(this, "Doan click", Toast.LENGTH_LONG).show() + if (binding.edtDoan.text.toString() == "A") { + // TODO + } + } + + binding.btnGiai.setOnClickListener { + Toast.makeText(this, "Giai click", Toast.LENGTH_LONG).show() + showDialog() + } + + binding.iconButton.setOnClickListener { + Toast.makeText(this, "Hint click", Toast.LENGTH_LONG).show() + } + + // Wheel + val wheelViewModel: WheelViewModel by viewModels() + val luckyWheelView: LuckyWheelView = binding.luckyWheel + + wheelViewModel.initLuckyItemList(this) + luckyWheelView.setData(wheelViewModel.luckyItemsList) + luckyWheelView.setLuckyRoundItemSelectedListener { + Toast.makeText(this, "on click", Toast.LENGTH_LONG).show() + goToWheelActivity() + } + luckyWheelView.isTouchEnabled = false + binding.llWheel.setOnClickListener { + goToWheelActivity() + } + + + } + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + private fun goToWheelActivity() { + val intent = Intent(this, WheelActivity::class.java) + startActivity(intent) + } + + private fun updateUi(gameModel: GameModel?) { + if (gameModel != null) { + gameModel.gameStatus = GameStatus.INPROGRESS + + updatePlayerList(gameModel) + updateCurrentQuestion(gameModel) + } + + } + + private fun showDialog() { + var m_Text: String = "" + val builder = AlertDialog.Builder(this) + builder.setTitle("Nhập lời giải cho câu hỏi") + val viewInflated = LayoutInflater.from(this).inflate(R.layout.dialog_edittext, null, false) + val input = viewInflated.findViewById(R.id.input) + builder.setView(viewInflated) + + builder.setPositiveButton(android.R.string.ok) { dialog, which -> + dialog.dismiss() + m_Text = input.text.toString() + } + + builder.setNegativeButton(android.R.string.cancel) { dialog, which -> + dialog.cancel() + } + + builder.show() + + + } + + private fun updateCurrentQuestion(gameModel: GameModel) { + binding.tvQuestion.text = gameModel.currentQuestion + } + + private fun updatePlayerList(gameModel: GameModel) { + when (gameModel.playersList.size) { + 1 -> { + // player1 + val colorResId = R.color.orange + val backgroundColor = ContextCompat.getColor(this, colorResId) + binding.cvPlayer1.setCardBackgroundColor(backgroundColor) + binding.imgLogo1.setImageResource(R.drawable.ic_man) + binding.tvPlayerName1.text = gameModel.playersList[0].name + binding.tvScore1.text = gameModel.playersList[0].score.toString() + } + 2 -> { + // player1 and player 2 + val colorResId = R.color.orange + val backgroundColor = ContextCompat.getColor(this, colorResId) + binding.imgLogo1.setImageResource(R.drawable.ic_man) + binding.imgLogo2.setImageResource(R.drawable.ic_man) + binding.tvPlayerName1.text = gameModel.playersList[0].name + binding.tvPlayerName2.text = gameModel.playersList[1].name + + binding.tvScore1.text = gameModel.playersList[0].score.toString() + binding.tvScore2.text = gameModel.playersList[1].score.toString() + + + } + + 3 -> { + // 3 player + val colorResId = R.color.orange + val backgroundColor = ContextCompat.getColor(this, colorResId) + binding.imgLogo1.setImageResource(R.drawable.ic_man) + binding.imgLogo2.setImageResource(R.drawable.ic_man) + binding.imgLogo3.setImageResource(R.drawable.ic_man) + binding.tvPlayerName1.text = gameModel.playersList[0].name + binding.tvPlayerName2.text = gameModel.playersList[1].name + binding.tvPlayerName3.text = gameModel.playersList[2].name + + binding.tvScore1.text = gameModel.playersList[0].score.toString() + binding.tvScore2.text = gameModel.playersList[1].score.toString() + binding.tvScore3.text = gameModel.playersList[2].score.toString() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/ui/SearchRoomActivity.kt b/app/src/main/java/com/example/chiecnonkydieu/ui/SearchRoomActivity.kt new file mode 100644 index 0000000..023a84a --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/ui/SearchRoomActivity.kt @@ -0,0 +1,76 @@ +package com.example.chiecnonkydieu.ui + +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.lifecycle.lifecycleScope +import com.example.chiecnonkydieu.R +import com.example.chiecnonkydieu.data.GameData +import com.example.chiecnonkydieu.data.Player +import com.example.chiecnonkydieu.databinding.ActivitySearchRoomBinding +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +class SearchRoomActivity : AppCompatActivity() { + private lateinit var binding: ActivitySearchRoomBinding + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySearchRoomBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.search_room_main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + + val toolbar: Toolbar = binding.toolbar + setSupportActionBar(toolbar) + + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setDisplayShowHomeEnabled(true) + + binding.btnSearchRoom.setOnClickListener { + lifecycleScope.launch { + val isJoined = lifecycleScope.async { + GameData.initialize(applicationContext) + GameData.joinOnlineGame( + player = Player(name = binding.edtName.text.toString()), + gameId = binding.edtMaPhong.text.toString().toInt() + ) + }.await() + + if (isJoined) { + goToWaitingRooom() + } else { + Toast.makeText(applicationContext, "Error when connect game", Toast.LENGTH_LONG).show() + } + } + + } + } + + fun goToWaitingRooom() { + try { + val intent = Intent(this, WaitingRoomActivity::class.java) + intent.putExtra("room_id", binding.edtMaPhong.text.toString()) + startActivity(intent) + } + catch (exception: Exception) { + Toast.makeText(this, binding.edtMaPhong.text, Toast.LENGTH_LONG).show() + } + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/ui/WaitingRoomActivity.kt b/app/src/main/java/com/example/chiecnonkydieu/ui/WaitingRoomActivity.kt new file mode 100644 index 0000000..b79b049 --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/ui/WaitingRoomActivity.kt @@ -0,0 +1,158 @@ +package com.example.chiecnonkydieu.ui + +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.core.content.ContextCompat +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope +import com.example.chiecnonkydieu.R +import com.example.chiecnonkydieu.data.GameData +import com.example.chiecnonkydieu.data.GameData.gameModel +import com.example.chiecnonkydieu.data.GameModel +import com.example.chiecnonkydieu.data.GameStatus +import com.example.chiecnonkydieu.data.Player +import com.example.chiecnonkydieu.databinding.ActivityWaitingRoomBinding +import com.google.firebase.database.DataSnapshot +import com.google.firebase.database.DatabaseError +import com.google.firebase.database.ValueEventListener +import kotlinx.coroutines.launch + +class WaitingRoomActivity : AppCompatActivity() { + private lateinit var binding: ActivityWaitingRoomBinding + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityWaitingRoomBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.waiting_room_main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + + val toolbar: Toolbar = binding.toolbar + setSupportActionBar(toolbar) + + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setDisplayShowHomeEnabled(true) + + + binding.tvMaPhong.text = intent.getStringExtra("room_id") +// fetch data from firebase + lifecycleScope.launch { + + GameData.fetchGameModel(intent.getStringExtra("room_id").toString().toInt()) + if (GameData.gameModel.value?.gameStatus == GameStatus.INPROGRESS) { + goToPlayingRoom() + } + + } + + // update ui with the new model + GameData.gameModel.observe(this, Observer { gameModel -> + updateUi(gameModel) + if (gameModel.gameStatus == GameStatus.INPROGRESS) { + goToPlayingRoom() + finish() + } + }) + + binding.btnStartGame.setOnClickListener { + val gameModel: GameModel? = GameData.gameModel.value + if (gameModel != null) { + gameModel.gameStatus = GameStatus.INPROGRESS + GameData.saveGameModel( + gameModel + ) + } + goToPlayingRoom() + } + + + + + } + + // Tu dong lang nghe su thay doi tu database trong vong doi cua activity +// override fun onStart() { +// super.onStart() +// +// GameData.database.addValueEventListener(object : +// ValueEventListener { +// override fun onDataChange(snapshot: DataSnapshot) { +// val gameModel: GameModel? = snapshot.getValue(GameModel::class.java) +// if (gameModel != null) { +// GameData.saveGameModel(gameModel) +// } +// } +// +// override fun onCancelled(error: DatabaseError) { +// // +// } +// }) +// } + + private fun updateUi(gameModel: GameModel?) { + if (gameModel != null) { + when (gameModel.playersList.size) { + 1 -> { + // player1 + val colorResId = R.color.orange + val backgroundColor = ContextCompat.getColor(this, colorResId) + binding.cvPlayer1.setCardBackgroundColor(backgroundColor) + binding.imgLogo1.setImageResource(R.drawable.ic_man) + binding.tvPlayerName1.text = gameModel.playersList[0].name + } + 2 -> { + // player1 and player 2 + val colorResId = R.color.orange + val backgroundColor = ContextCompat.getColor(this, colorResId) + binding.cvPlayer1.setCardBackgroundColor(backgroundColor) + binding.cvPlayer2.setCardBackgroundColor(backgroundColor) + binding.imgLogo1.setImageResource(R.drawable.ic_man) + binding.imgLogo2.setImageResource(R.drawable.ic_man) + binding.tvPlayerName1.text = gameModel.playersList[0].name + binding.tvPlayerName2.text = gameModel.playersList[1].name + + } + + 3 -> { + // 3 player + val colorResId = R.color.orange + val backgroundColor = ContextCompat.getColor(this, colorResId) + binding.cvPlayer1.setCardBackgroundColor(backgroundColor) + binding.cvPlayer2.setCardBackgroundColor(backgroundColor) + binding.cvPlayer3.setCardBackgroundColor(backgroundColor) + binding.imgLogo1.setImageResource(R.drawable.ic_man) + binding.imgLogo2.setImageResource(R.drawable.ic_man) + binding.imgLogo3.setImageResource(R.drawable.ic_man) + binding.tvPlayerName1.text = gameModel.playersList[0].name + binding.tvPlayerName2.text = gameModel.playersList[1].name + binding.tvPlayerName3.text = gameModel.playersList[2].name + } + } + + } + + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + + private fun goToPlayingRoom() { + val intent = Intent(this, PlayingRoomActivity::class.java).apply { + putExtra("room_id", binding.tvMaPhong.text.toString()) + flags = Intent.FLAG_ACTIVITY_SINGLE_TOP + } + startActivity(intent) + } +} diff --git a/app/src/main/java/com/example/chiecnonkydieu/ui/wheel/WheelActivity.kt b/app/src/main/java/com/example/chiecnonkydieu/ui/wheel/WheelActivity.kt new file mode 100644 index 0000000..25df369 --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/ui/wheel/WheelActivity.kt @@ -0,0 +1,93 @@ +package com.example.chiecnonkydieu.ui.wheel + +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.os.CountDownTimer +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.get +import com.example.chiecnonkydieu.R +import com.example.chiecnonkydieu.databinding.ActivityWheelBinding +import rubikstudio.library.LuckyWheelView +import rubikstudio.library.model.LuckyItem + +class WheelActivity : AppCompatActivity() { + private lateinit var binding: ActivityWheelBinding + private lateinit var countDownTimer: CountDownTimer + + @RequiresApi(Build.VERSION_CODES.O) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityWheelBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + val toolbar: Toolbar = binding.toolbar + setSupportActionBar(toolbar) + + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setDisplayShowHomeEnabled(true) + + val wheelViewModel: WheelViewModel by viewModels() + val luckyWheelView: LuckyWheelView = binding.luckyWheel + + wheelViewModel.initLuckyItemList(this) + luckyWheelView.setData(wheelViewModel.luckyItemsList) + + luckyWheelView.isTouchEnabled = false + luckyWheelView.setOnTouchListener { v, event -> + val indexAns = wheelViewModel.getIndexAfterRotate() + luckyWheelView.setRound(3) + luckyWheelView.startLuckyWheelWithTargetIndex(indexAns) + Toast.makeText(this, wheelViewModel.getStringItemAtIndex(indexAns), Toast.LENGTH_LONG).show() + return@setOnTouchListener true + } + + + binding.btnQuay.setOnClickListener { + val indexAns = wheelViewModel.getIndexAfterRotate() + luckyWheelView.setRound(3) + luckyWheelView.startLuckyWheelWithTargetIndex(indexAns) + Toast.makeText(this, wheelViewModel.getStringItemAtIndex(indexAns), Toast.LENGTH_LONG).show() +// Toast.makeText(this, wheelViewModel.luckyItemsList.get(3).secondaryText, Toast.LENGTH_LONG).show() + } + + // count down timer + countDownTimer = object : CountDownTimer(7000, 1000) { + override fun onTick(millisUntilFinished: Long) { + val secondsLeft = millisUntilFinished / 1000 + binding.tvConLaiXGiay.text = String.format(getString(R.string.con_lai_x_giay), secondsLeft.toString()) + } + + override fun onFinish() { + binding.tvConLaiXGiay.text = String.format(getString(R.string.con_lai_x_giay), 0) + binding.btnQuay.performClick() + + } + } + + countDownTimer.start() + + } + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + + override fun onDestroy() { + super.onDestroy() + countDownTimer.cancel() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/ui/wheel/WheelViewModel.kt b/app/src/main/java/com/example/chiecnonkydieu/ui/wheel/WheelViewModel.kt new file mode 100644 index 0000000..3153000 --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/ui/wheel/WheelViewModel.kt @@ -0,0 +1,87 @@ +package com.example.chiecnonkydieu.ui.wheel + +import android.content.Context +import android.graphics.Color +import androidx.core.content.ContextCompat +import androidx.lifecycle.ViewModel +import com.example.chiecnonkydieu.R +import rubikstudio.library.model.LuckyItem +class WheelViewModel: ViewModel() { + private val _luckyItemsList: MutableList = mutableListOf() + val luckyItemsList:List = _luckyItemsList + + fun initLuckyItemList(context: Context) { + val luckyItem: LuckyItem = LuckyItem() + luckyItem.secondaryText = "100" + luckyItem.color = ContextCompat.getColor(context, R.color.purple_300) + _luckyItemsList.add(luckyItem) + + val luckyItem2: LuckyItem = LuckyItem() + luckyItem2.secondaryText = "400" + luckyItem2.color = ContextCompat.getColor(context, R.color.green) + _luckyItemsList.add(luckyItem2) + + val luckyItem3: LuckyItem = LuckyItem() + luckyItem3.secondaryText = "800" + luckyItem3.color = ContextCompat.getColor(context, R.color.blue_200) + _luckyItemsList.add(luckyItem3) + + val luckyItem4: LuckyItem = LuckyItem() + luckyItem4.topText = "EXTRA TURN" + luckyItem4.icon = R.drawable.ic_man + luckyItem4.color = ContextCompat.getColor(context, R.color.purple_500) + _luckyItemsList.add(luckyItem4) + + val luckyItem5: LuckyItem = LuckyItem() + luckyItem5.secondaryText = "1200" + luckyItem5.color = ContextCompat.getColor(context, R.color.gray) + _luckyItemsList.add(luckyItem5) + + val luckyItem6: LuckyItem = LuckyItem() + luckyItem6.secondaryText = "600" + luckyItem6.color = ContextCompat.getColor(context, R.color.blue_200) + + _luckyItemsList.add(luckyItem6) + + val luckyItem7: LuckyItem = LuckyItem() + luckyItem7.topText = "MISS TURN" + luckyItem7.icon = R.drawable.ic_man + luckyItem7.color = ContextCompat.getColor(context, R.color.purple_500) + _luckyItemsList.add(luckyItem7) + + val luckyItem8: LuckyItem = LuckyItem() + luckyItem8.secondaryText = "800" + luckyItem8.color = ContextCompat.getColor(context, R.color.green) + _luckyItemsList.add(luckyItem8) + + val luckyItem9: LuckyItem = LuckyItem() + luckyItem9.secondaryText = "1500" + luckyItem9.color = ContextCompat.getColor(context, R.color.purple_300) + _luckyItemsList.add(luckyItem9) + + val luckyItem10: LuckyItem = LuckyItem() + luckyItem10.secondaryText = "400" + luckyItem10.color = ContextCompat.getColor(context, R.color.green) + _luckyItemsList.add(luckyItem10) + + val luckyItem11: LuckyItem = LuckyItem() + luckyItem11.topText = "ITEM" + luckyItem11.icon = R.drawable.ic_wheel + luckyItem11.color = ContextCompat.getColor(context, R.color.orange) + _luckyItemsList.add(luckyItem11) + } + + fun getIndexAfterRotate(): Int { + // TODO + val size = _luckyItemsList.size - 1 + return (0 .. size).random() + } + fun getStringItemAtIndex(index: Int): String { + return if (!_luckyItemsList[index].secondaryText.isNullOrEmpty()) { + _luckyItemsList[index].secondaryText + } + else { + _luckyItemsList[index].topText + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/chiecnonkydieu/ui/wheelSpinnerViewModel/WheelSpinnerViewModel.kt b/app/src/main/java/com/example/chiecnonkydieu/ui/wheelSpinnerViewModel/WheelSpinnerViewModel.kt new file mode 100644 index 0000000..d584f86 --- /dev/null +++ b/app/src/main/java/com/example/chiecnonkydieu/ui/wheelSpinnerViewModel/WheelSpinnerViewModel.kt @@ -0,0 +1,46 @@ +package com.example.chiecnonkydieu.ui.wheelSpinnerViewModel + +import com.example.chiecnonkydieu.R + +import android.content.Context +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import rubikstudio.library.LuckyWheelView +import rubikstudio.library.model.LuckyItem +import java.util.* + +class WheelSpinnerViewModel ( itemList: List, context: Context ): ViewModel() { + private val luckyItemList = MutableLiveData>() + val liveLuckyItemList: LiveData> + get() = luckyItemList + private val spinIndex = MutableLiveData() + val liveSpinIndex : LiveData + get() = spinIndex + private val colors = arrayOf(R.color.orange, R.color.black) + + init { + val listItems = mutableListOf() + + for (i in itemList.indices) run { + val luckyItem = LuckyItem() + luckyItem.secondaryText = itemList[i] + luckyItem.topText = ( i + 1 ).toString() + luckyItem.color = context.getColor( this.colors[if (i % 2 == 0) 0 else 1] ) + listItems.add(luckyItem) + } + + this.luckyItemList.value = listItems + } + + fun spinWheel() { + val rand = Random() + spinIndex.value = rand.nextInt(this.luckyItemList.value!!.size - 1) + 0 + } + + fun doneSpinning(){ + spinIndex.value = -1 + } + +} + diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml new file mode 100644 index 0000000..99f85de --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_back.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_center_wheel.png b/app/src/main/res/drawable/ic_center_wheel.png new file mode 100644 index 0000000..5063bfc Binary files /dev/null and b/app/src/main/res/drawable/ic_center_wheel.png differ diff --git a/app/src/main/res/drawable/ic_cursor.png b/app/src/main/res/drawable/ic_cursor.png new file mode 100644 index 0000000..c275eb4 Binary files /dev/null and b/app/src/main/res/drawable/ic_cursor.png differ diff --git a/app/src/main/res/drawable/ic_hint.png b/app/src/main/res/drawable/ic_hint.png new file mode 100644 index 0000000..f04f2e6 Binary files /dev/null and b/app/src/main/res/drawable/ic_hint.png differ diff --git a/app/src/main/res/drawable/ic_loading.png b/app/src/main/res/drawable/ic_loading.png new file mode 100644 index 0000000..a230e78 Binary files /dev/null and b/app/src/main/res/drawable/ic_loading.png differ diff --git a/app/src/main/res/drawable/ic_man.png b/app/src/main/res/drawable/ic_man.png new file mode 100644 index 0000000..1c927a4 Binary files /dev/null and b/app/src/main/res/drawable/ic_man.png differ diff --git a/app/src/main/res/drawable/ic_roulette.png b/app/src/main/res/drawable/ic_roulette.png new file mode 100644 index 0000000..a249e61 Binary files /dev/null and b/app/src/main/res/drawable/ic_roulette.png differ diff --git a/app/src/main/res/drawable/ic_wheel.png b/app/src/main/res/drawable/ic_wheel.png new file mode 100644 index 0000000..d61a8dc Binary files /dev/null and b/app/src/main/res/drawable/ic_wheel.png differ diff --git a/app/src/main/res/drawable/ic_woman.png b/app/src/main/res/drawable/ic_woman.png new file mode 100644 index 0000000..23fcf9e Binary files /dev/null and b/app/src/main/res/drawable/ic_woman.png differ diff --git a/app/src/main/res/drawable/orange_card.xml b/app/src/main/res/drawable/orange_card.xml new file mode 100644 index 0000000..f326b9e --- /dev/null +++ b/app/src/main/res/drawable/orange_card.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/purple_gradient.xml b/app/src/main/res/drawable/purple_gradient.xml new file mode 100644 index 0000000..01c0d84 --- /dev/null +++ b/app/src/main/res/drawable/purple_gradient.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_button.xml b/app/src/main/res/drawable/rounded_button.xml new file mode 100644 index 0000000..9dfe968 --- /dev/null +++ b/app/src/main/res/drawable/rounded_button.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_button_secondary.xml b/app/src/main/res/drawable/rounded_button_secondary.xml new file mode 100644 index 0000000..f326b9e --- /dev/null +++ b/app/src/main/res/drawable/rounded_button_secondary.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_green.xml b/app/src/main/res/drawable/rounded_green.xml new file mode 100644 index 0000000..fa65d73 --- /dev/null +++ b/app/src/main/res/drawable/rounded_green.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/open_sans.xml b/app/src/main/res/font/open_sans.xml new file mode 100644 index 0000000..f9284b2 --- /dev/null +++ b/app/src/main/res/font/open_sans.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/font/open_sans_bold.xml b/app/src/main/res/font/open_sans_bold.xml new file mode 100644 index 0000000..eba352b --- /dev/null +++ b/app/src/main/res/font/open_sans_bold.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/font/open_sans_semibold.xml b/app/src/main/res/font/open_sans_semibold.xml new file mode 100644 index 0000000..13a062d --- /dev/null +++ b/app/src/main/res/font/open_sans_semibold.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/layout/activity_create_room.xml b/app/src/main/res/layout/activity_create_room.xml new file mode 100644 index 0000000..50a71bf --- /dev/null +++ b/app/src/main/res/layout/activity_create_room.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + \ 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 86a5d97..85e4b3b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,15 +5,91 @@ android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@drawable/purple_gradient" tools:context=".MainActivity"> + + + + app:layout_constraintTop_toBottomOf="@+id/tv_title" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_playing_room.xml b/app/src/main/res/layout/activity_playing_room.xml new file mode 100644 index 0000000..9976548 --- /dev/null +++ b/app/src/main/res/layout/activity_playing_room.xml @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search_room.xml b/app/src/main/res/layout/activity_search_room.xml new file mode 100644 index 0000000..079482e --- /dev/null +++ b/app/src/main/res/layout/activity_search_room.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_waiting_room.xml b/app/src/main/res/layout/activity_waiting_room.xml new file mode 100644 index 0000000..af56bfe --- /dev/null +++ b/app/src/main/res/layout/activity_waiting_room.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_wheel.xml b/app/src/main/res/layout/activity_wheel.xml new file mode 100644 index 0000000..77346c7 --- /dev/null +++ b/app/src/main/res/layout/activity_wheel.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_edittext.xml b/app/src/main/res/layout/dialog_edittext.xml new file mode 100644 index 0000000..15f8e9f --- /dev/null +++ b/app/src/main/res/layout/dialog_edittext.xml @@ -0,0 +1,22 @@ + + + + + + + + + \ 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 c8524cd..6ce16a8 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,4 +2,15 @@ #FF000000 #FFFFFFFF + + #95E1D3 + #FEC14E + #EAFFD0 + + #A35DFE + #D28FFF + #D9D9D9 + + #11E132 + \ No newline at end of file diff --git a/app/src/main/res/values/font_certs.xml b/app/src/main/res/values/font_certs.xml new file mode 100644 index 0000000..d2226ac --- /dev/null +++ b/app/src/main/res/values/font_certs.xml @@ -0,0 +1,17 @@ + + + + @array/com_google_android_gms_fonts_certs_dev + @array/com_google_android_gms_fonts_certs_prod + + + + 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 + + + diff --git a/app/src/main/res/values/preloaded_fonts.xml b/app/src/main/res/values/preloaded_fonts.xml new file mode 100644 index 0000000..71de273 --- /dev/null +++ b/app/src/main/res/values/preloaded_fonts.xml @@ -0,0 +1,8 @@ + + + + @font/open_sans + @font/open_sans_bold + @font/open_sans_semibold + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dcd5f47..0b807f7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,28 @@ ChiecNonKyDieu + CHIẾC NÓN KỲ DIỆU + + BẮT ĐẦU + TẠO PHÒNG + TÌM PHÒNG + wheel logo + + Tạo phòng + Tìm phòng + Tên Người chơi + Mã phòng + + Đợi người chơi + Đang đợi người chơi + Vòng 1 + Thủ đô của Việt Nam ở đâu? + Nhập 1 ký tự + Đoán + Giải + Quay + Hint + + Đến lượt của bạn + Còn lại %s s + Nhập lời giải \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 2107749..7548677 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,10 @@ buildscript { dependencies { classpath(libs.google.services) } + repositories { + maven { url = uri("https://www.jitpack.io") } + } + } // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { diff --git a/settings.gradle.kts b/settings.gradle.kts index c31862a..741499a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,6 +16,9 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { + setUrl("https://jitpack.io") + } } }