-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[둘리] 1, 2단계 영화 티켓 예매 제출합니다. #7
Changes from all commits
81ab027
545de51
766d546
4c79b1a
4396e2c
282882b
4690eae
2bc5a77
15cf193
c75d5a7
e38faa0
2616c9a
7c5e91f
761850e
013a294
adf25b7
f50a2ce
48a66c5
47f12c8
443e903
e7db664
aa74fa9
c05ff0e
fc093c7
3f5cc8f
b512714
6d2199c
520d74b
3ddf00b
fe47ef3
5525f7b
7dce42c
70e7f6b
6b3843c
c881fba
4d17d10
10f416c
303b877
ed85463
452126c
77afa95
54b5c30
8609c35
2e67294
187af84
6fc6324
a5e2e98
37cf719
b8c06a2
e2c4c55
0fe291d
dc6ad79
e062f6f
9864e56
5cca9a1
a45c442
9f8e452
d04bd6c
5336de6
77cd778
1c36e77
186d6f6
b1bffce
b13a913
f8c3245
ae36175
f2bfce9
1dc76f1
ac7b7e6
39215c6
b89051c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,24 @@ | ||
# android-movie-ticket | ||
# android-movie-ticket | ||
|
||
## 액티비티 | ||
- MovieListActivity | ||
- TicketingActivity | ||
- MovieTicketActivity | ||
|
||
## 어댑터 | ||
- MoviesAdapter | ||
|
||
## 데이터 | ||
- Movie | ||
- 이미지, 제목, 상영일(PlayingTimes), 러닝타임, 소개 | ||
- TicketingInfo | ||
- 영화 이름, 상영일, 몇명, 가격, 무슨 결제 | ||
- Price | ||
- 음수 체크 | ||
- 티켓 한 장의 가격은 13000원 | ||
- 영화 가격에 할인을 적용한다. | ||
- Discount 구현 클래스를 리스트로 받는다. | ||
- PlayingTimes | ||
- 날짜-상영시간 map 타입으로 가지고 있다. | ||
- Discount (인터페이스) | ||
- calculate 메소드 |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package woowacourse.movie.activity.moviedetail | ||
|
||
import android.R | ||
import android.view.View | ||
import android.widget.AdapterView | ||
import android.widget.ArrayAdapter | ||
import android.widget.Spinner | ||
import woowacourse.movie.util.getKeyFromIndex | ||
import woowacourse.movie.util.getOrEmptyList | ||
import java.time.LocalDate | ||
import java.time.LocalTime | ||
|
||
class DateSpinnerListener(private val playingTimes: Map<LocalDate, List<LocalTime>>, private val spinnerTime: Spinner) : AdapterView.OnItemSelectedListener { | ||
override fun onItemSelected(adapterView: AdapterView<*>?, view: View?, index: Int, p3: Long) { | ||
val times = playingTimes.getOrEmptyList(playingTimes.getKeyFromIndex(index)) | ||
spinnerTime.adapter = ArrayAdapter(spinnerTime.context, R.layout.simple_spinner_item, times) | ||
} | ||
|
||
override fun onNothingSelected(p0: AdapterView<*>?) { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package woowacourse.movie.activity.moviedetail | ||
|
||
import android.os.Bundle | ||
import android.view.MenuItem | ||
import android.widget.Spinner | ||
import android.widget.TextView | ||
import android.widget.Toast | ||
import androidx.appcompat.app.AppCompatActivity | ||
import woowacourse.movie.R | ||
import woowacourse.movie.model.MovieModel | ||
import woowacourse.movie.util.getSerializableExtraCompat | ||
|
||
class MovieDetailActivity : AppCompatActivity() { | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_movie_detail) | ||
val movie: MovieModel? = intent.getSerializableExtraCompat(MOVIE_KEY) | ||
if (movie == null) { | ||
Toast.makeText(this, DATA_LOADING_ERROR_MESSAGE, Toast.LENGTH_LONG).show() | ||
finish() | ||
return | ||
} | ||
MovieDetailView(findViewById(R.id.layout_detail_info)).set(movie) | ||
ReservationInfoView(findViewById(R.id.layout_reservation_info)).set(savedInstanceState, movie) | ||
Comment on lines
+17
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 흐름도 분리도 아주 깔끔해졌네요 👍 아래는 조금 어렵지만, 도전해보셔도 좋고 공부만 해보셔도 좋아요 :) <androidx.constraintlayout.widget.ConstraintLayout>
<...MovieDetailView
android:....
android:.... />
<...ReservationInfoView
android:....
android:.... />
</androidx.constraintlayout.widget.ConstraintLayout> |
||
supportActionBar?.setDisplayHomeAsUpEnabled(true) | ||
} | ||
|
||
override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||
return when (item.itemId) { | ||
android.R.id.home -> { | ||
finish() | ||
true | ||
} | ||
else -> { | ||
super.onOptionsItemSelected(item) | ||
} | ||
} | ||
} | ||
|
||
override fun onSaveInstanceState(outState: Bundle) { | ||
super.onSaveInstanceState(outState) | ||
val countText = findViewById<TextView>(R.id.text_count) | ||
val spinnerDate = findViewById<Spinner>(R.id.spinner_date) | ||
val spinnerTime = findViewById<Spinner>(R.id.spinner_time) | ||
outState.putInt(COUNT_KEY, countText.text.toString().toInt()) | ||
outState.putInt(SPINNER_DATE_KEY, spinnerDate.selectedItemPosition) | ||
outState.putInt(SPINNER_TIME_KEY, spinnerTime.selectedItemPosition) | ||
} | ||
|
||
companion object { | ||
private const val DATA_LOADING_ERROR_MESSAGE = "데이터가 로딩되지 않았습니다. 다시 시도해주세요." | ||
const val MOVIE_KEY = "MOVIE" | ||
const val COUNT_KEY = "COUNT" | ||
const val SPINNER_DATE_KEY = "SPINNER_DATE" | ||
const val SPINNER_TIME_KEY = "SPINNER_TIME" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package woowacourse.movie.activity.moviedetail | ||
|
||
import android.view.ViewGroup | ||
import android.widget.ImageView | ||
import android.widget.TextView | ||
import woowacourse.movie.R | ||
import woowacourse.movie.model.MovieModel | ||
import java.time.LocalDate | ||
import java.time.format.DateTimeFormatter | ||
|
||
class MovieDetailView(private val viewGroup: ViewGroup) { | ||
fun set(movie: MovieModel) { | ||
setImageView(movie.image) | ||
setTitle(movie.title) | ||
setPlayingDate(movie.startDate, movie.endDate) | ||
setRunningTime(movie.runningTime) | ||
setDescription(movie.description) | ||
} | ||
Comment on lines
+12
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. set을 할 때마다 findViewId를 실행해주어야겠네요. |
||
|
||
private fun setDescription(description: String) { | ||
viewGroup.findViewById<TextView>(R.id.text_description).text = description | ||
} | ||
|
||
private fun setRunningTime(runningTime: Int) { | ||
viewGroup.findViewById<TextView>(R.id.text_running_time).text = viewGroup.context.getString(R.string.running_time, runningTime) | ||
} | ||
|
||
private fun setPlayingDate(startDate: LocalDate, endDate: LocalDate) { | ||
viewGroup.findViewById<TextView>(R.id.text_playing_date).text = viewGroup.context.getString( | ||
R.string.playing_date_range, | ||
DateTimeFormatter.ofPattern(viewGroup.context.getString(R.string.date_format)).format(startDate), | ||
DateTimeFormatter.ofPattern(viewGroup.context.getString(R.string.date_format)).format(endDate) | ||
) | ||
} | ||
|
||
private fun setTitle(title: String) { | ||
viewGroup.findViewById<TextView>(R.id.text_title).text = title | ||
} | ||
|
||
private fun setImageView(image: Int) { | ||
viewGroup.findViewById<ImageView>(R.id.img_movie).setImageResource(image) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package woowacourse.movie.activity.moviedetail | ||
|
||
import android.content.Intent | ||
import android.os.Bundle | ||
import android.view.ViewGroup | ||
import android.widget.ArrayAdapter | ||
import android.widget.Button | ||
import android.widget.Spinner | ||
import android.widget.TextView | ||
import woowacourse.movie.R | ||
import woowacourse.movie.activity.ticketresult.TicketResultActivity | ||
import woowacourse.movie.domain.policy.DiscountPolicies | ||
import woowacourse.movie.domain.ticket.Price | ||
import woowacourse.movie.domain.ticket.Ticket | ||
import woowacourse.movie.model.MovieModel | ||
import woowacourse.movie.model.toPresentation | ||
import woowacourse.movie.util.getKeyFromIndex | ||
import woowacourse.movie.util.getOrEmptyList | ||
import java.time.LocalDate | ||
import java.time.LocalTime | ||
|
||
class ReservationInfoView(private val viewGroup: ViewGroup) { | ||
|
||
fun set(savedInstanceState: Bundle?, movie: MovieModel) { | ||
val savedCount = savedInstanceState?.getInt(MovieDetailActivity.COUNT_KEY) ?: DEFAULT_COUNT | ||
val savedDate = | ||
savedInstanceState?.getInt(MovieDetailActivity.SPINNER_DATE_KEY) ?: DEFAULT_POSITION | ||
val savedTime = | ||
savedInstanceState?.getInt(MovieDetailActivity.SPINNER_TIME_KEY) ?: DEFAULT_POSITION | ||
|
||
setCount(savedCount) | ||
setMinusButton() | ||
setPlusButton() | ||
setReserveButton(movie.title) | ||
setDateSpinner(savedDate, movie.playingDateTimes) | ||
setTimeSpinner( | ||
savedTime, | ||
movie.playingDateTimes.getOrEmptyList(movie.playingDateTimes.getKeyFromIndex(savedDate)) | ||
) | ||
} | ||
|
||
private fun setReserveButton(title: String) { | ||
viewGroup.findViewById<Button>(R.id.btn_reserve).setOnClickListener { | ||
val intent = Intent(it.context, TicketResultActivity::class.java) | ||
val ticket = Ticket.of( | ||
DiscountPolicies.policies, | ||
title, | ||
viewGroup.findViewById<Spinner>(R.id.spinner_date).selectedItem as LocalDate, | ||
viewGroup.findViewById<Spinner>(R.id.spinner_time).selectedItem as LocalTime, | ||
viewGroup.findViewById<TextView>(R.id.text_count).text.toString().toInt(), | ||
Price() | ||
) | ||
intent.putExtra(TicketResultActivity.INFO_KEY, ticket.toPresentation()) | ||
it.context.startActivity(intent) | ||
Comment on lines
+53
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 View 객체를 재활용해야할 때 어떤 문제가 발생할 수 있을까요? |
||
} | ||
} | ||
|
||
private fun setTimeSpinner(savedTimePosition: Int, times: List<LocalTime>) { | ||
val timeSpinner = viewGroup.findViewById<Spinner>(R.id.spinner_time) | ||
timeSpinner.adapter = SpinnerAdapter(times) | ||
timeSpinner.setSelection(savedTimePosition) | ||
} | ||
|
||
private fun setDateSpinner( | ||
savedDatePosition: Int, | ||
playingTimes: Map<LocalDate, List<LocalTime>> | ||
) { | ||
val dateSpinner = viewGroup.findViewById<Spinner>(R.id.spinner_date) | ||
val timeSpinner = viewGroup.findViewById<Spinner>(R.id.spinner_time) | ||
dateSpinner.adapter = SpinnerAdapter(playingTimes.keys.toList()) | ||
dateSpinner.setSelection(savedDatePosition, false) | ||
dateSpinner.onItemSelectedListener = DateSpinnerListener(playingTimes, timeSpinner) | ||
} | ||
|
||
private fun setMinusButton() { | ||
val minusButton = viewGroup.findViewById<Button>(R.id.btn_minus) | ||
val countView = viewGroup.findViewById<TextView>(R.id.text_count) | ||
minusButton.setOnClickListener { | ||
val count = countView.text.toString().toInt() | ||
if (count > 1) countView.text = (count - 1).toString() | ||
} | ||
} | ||
|
||
private fun setPlusButton() { | ||
val plusButton = viewGroup.findViewById<Button>(R.id.btn_plus) | ||
val countView = viewGroup.findViewById<TextView>(R.id.text_count) | ||
plusButton.setOnClickListener { | ||
val count = countView.text.toString().toInt() | ||
countView.text = (count + 1).toString() | ||
} | ||
} | ||
|
||
private fun setCount(savedCount: Int) { | ||
val countView = viewGroup.findViewById<TextView>(R.id.text_count) | ||
countView.text = savedCount.toString() | ||
} | ||
|
||
private fun <T> SpinnerAdapter(items: List<T>) = | ||
ArrayAdapter(viewGroup.context, android.R.layout.simple_spinner_item, items).apply { | ||
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) | ||
} | ||
|
||
companion object { | ||
private const val DEFAULT_COUNT = 1 | ||
private const val DEFAULT_POSITION = 0 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package woowacourse.movie.activity.movielist | ||
|
||
import android.content.Intent | ||
import android.os.Bundle | ||
import android.view.View | ||
import android.widget.ListView | ||
import androidx.appcompat.app.AppCompatActivity | ||
import woowacourse.movie.R | ||
import woowacourse.movie.activity.moviedetail.MovieDetailActivity | ||
import woowacourse.movie.model.MovieModel | ||
import woowacourse.movie.model.toPresentation | ||
import woowacourse.movie.util.DummyData | ||
|
||
class MovieListActivity : AppCompatActivity() { | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_movie_list) | ||
|
||
val listView = findViewById<ListView>(R.id.list_view) | ||
val adapter = MovieListAdapter( | ||
DummyData.movies.map { it.toPresentation(R.drawable.img) }, | ||
object : MovieListItemListener { | ||
override fun onClick(movie: MovieModel, view: View) { | ||
val intent = Intent(view.context, MovieDetailActivity::class.java) | ||
intent.putExtra(MovieDetailActivity.MOVIE_KEY, movie) | ||
view.context.startActivity(intent) | ||
} | ||
} | ||
Comment on lines
+22
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분은 어떤 이유로 setOnClickLisntener { } 처럼 바로 람다로 표현하지 못할 수 밖에 없었을까요? 🤔 |
||
) | ||
listView.adapter = adapter | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package woowacourse.movie.activity.movielist | ||
|
||
import android.content.Context | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.View.OnClickListener | ||
import android.view.ViewGroup | ||
import android.widget.BaseAdapter | ||
import android.widget.Button | ||
import android.widget.ImageView | ||
import android.widget.TextView | ||
import woowacourse.movie.R | ||
import woowacourse.movie.model.MovieModel | ||
import java.time.format.DateTimeFormatter | ||
|
||
class MovieListAdapter(private val movies: List<MovieModel>, private val listener: MovieListItemListener) : BaseAdapter() { | ||
private val viewHolders: MutableMap<View, ViewHolder> = mutableMapOf() | ||
Comment on lines
+16
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 더 이상 tag에 저장하지 않게 되었네요 👍 아래는 구현하지 않고 고민해보세요 :)
위 내용들은 RecyclerView에서 어떻게 해결했을 지도 잘 참고해보세요 😊 |
||
override fun getCount(): Int { | ||
return movies.size | ||
} | ||
|
||
override fun getItem(position: Int): Any { | ||
return movies[position] | ||
} | ||
|
||
override fun getItemId(position: Int): Long { | ||
return position.toLong() | ||
} | ||
|
||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { | ||
val view = convertView ?: LayoutInflater.from(parent?.context).inflate(R.layout.movie_item, null) | ||
if (viewHolders[view] == null) viewHolders[view] = getViewHolder(view) | ||
val movie = getItem(position) as MovieModel | ||
viewHolders[view]?.set(movie, parent?.context) { | ||
listener.onClick(movie, it) | ||
} | ||
return view | ||
} | ||
|
||
private fun getViewHolder(view: View): ViewHolder = ViewHolder( | ||
view.findViewById(R.id.img_movie), | ||
view.findViewById(R.id.text_title), | ||
view.findViewById(R.id.text_playing_date), | ||
view.findViewById(R.id.text_running_time), | ||
view.findViewById(R.id.btn_reserve) | ||
) | ||
private class ViewHolder( | ||
val image: ImageView, | ||
val title: TextView, | ||
val playingDate: TextView, | ||
val runningTime: TextView, | ||
val reserveButton: Button | ||
) { | ||
fun set(movie: MovieModel, context: Context?, clickListener: OnClickListener) { | ||
image.setImageResource(movie.image) | ||
title.text = movie.title | ||
playingDate.text = context?.getString( | ||
R.string.playing_date_range, | ||
DateTimeFormatter.ofPattern(context.getString(R.string.date_format)).format(movie.startDate), | ||
DateTimeFormatter.ofPattern(context.getString(R.string.date_format)).format(movie.endDate) | ||
) | ||
runningTime.text = context?.getString(R.string.running_time, movie.runningTime) | ||
reserveButton.setOnClickListener(clickListener) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 스피너 리스너는 다른 스피너에 크게 의존적이에요.
동일한 스피너 리스너를 재활용할 수 있게 할 수 있을까요?
혹은 이 리스너만 따로 클래스로 분리되는 게 적절할지도 고민해보면 좋겠어요 :)