-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* docs: 클래스와 액티비티 설계도 작성 * feat: Movie 데이터 클래스 작성 * docs: 설계도 수정 * feat: Price 클래스 구현 * feat: TicketingInfo 클래스 구현 * refactor: TicketingInfo name->title로 수정 * feat: ListView, ListAdapter 구현 * feat: 문자열 상수 @string으로 분할 * feat: MovieListActivity 구현 * feat: activity_ticketing xml 구현 * refactor: xml 더미데이터 삭제 * refactor: Price 클래스 value class 로 변경 * feat: TicketingActivity 구현 * feat: activity_movie_ticket xml 구현 * feat: MovieTicketActivity 구현 * refactor: activity_movie_ticket.xml 글자 볼드 처리 수정 * refactor: ViewHolder 적용 * refactor: 불필요한 MainActivity 삭제 * refactor: 상영일, 러닝타임 문자 출력 수정 * refactor: activity_ticketing.xml 본문 스크롤 되도록 수정 * docs: 클래스 설계도 수정 * feat: PlayingTimes 구현 * refactor: PlayintDate, PlayingTime 따로 받도록 수정 * refactor: 직렬화되도록 수정 * feat: 날짜 시간 선택 spinner 구현 * feat: 할인 정책 구현 * feat: 화면 회전 시 데이터 유지 구현 * refactor: 영화 더미 데이터 가져오는 함수 분리 * refactor: 로직 함수로 분리 * feat: Formatter 구현 * feat: Intent getSerializable 확장함수 구현 * refactor: MovieListAdapter, MovieTicketActivity 리팩터링 * test: FormatterTest 구현 * refactor: TicketingActivity.kt 코드 리팩토링 * refactor: 패키지 구조 분리 및 액티비티 명 수정 * refactor: SpinnerListener, Keys 분리 * refactor: DummyData 분리 * refactor: getString 필요없는 format 함수 사용 삭제 * refactor: require 수정 * refactor: ViewHolder 필드들 nullable인 것 수정 * refactor: PlayingTimes 리팩터링 * fix: Exception 발생 버그 수정 * refactor: Policies 따로 분할, 범용적으로 사용할 수 있도록 수정 * test: DiscountPolicy 클래스 변경으로 인한 테스트 수정 및 추가 * refactor: Formatter 삭제 * refactor: 모든 layout Linear에서 Constraint로 변경 * refactor: ktlintFormat 적용 * refactor: FormatterTest 삭제 * refactor: null일시 토스트 띄운 후 뒤로가도록 수정 * refactor: 확장함수명 변경 * refactor: 패키지 변경 및 뷰 값 세팅 클래스 분리 * refactor: 패키지 변경 * refactor: MovieDetailActivity, TicketResultActivity 함수 분리 * refactor: DummyData 추가, 변수명 변경 * refactor: MovieDTO 추가 * refactor: Key들 위치 변경, Keys object 삭제 * refactor: 확장함수명 변경 * refactor: else문 삭제 * refactor: scope function run 대신 with 사용 * refactor: package 이동, MovieDTO 및 Mapper 수정 * refactor: view를 객체 내부에서 찾도록 변경 * refactor: key가 없으면 빈 리스트를 반환하는 Map 확장함수 구현 * refactor: 모듈 분리 * refactor: ViewHolders Map 생성, set 함수 이동 * refactor: MovieListItemListener 생성 후 Listener 분할 * refactor: getKeyFromIndex Map 확장함수 생성 * refactor: MovieDTO -> MovieModel 네이밍 변경 * refactor: View Setting 함수 하나로 합치기 * refactor: SpinnerAdapter 함수 분리 * refactor: TicketingInfo -> Ticket으로 변경, payment 삭제 * refactor: TicketModel 생성, 도메인 객체 의존성 제거 --------- Co-authored-by: whk06061 <[email protected]>
- Loading branch information
Showing
45 changed files
with
1,288 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
21 changes: 21 additions & 0 deletions
21
app/src/main/java/woowacourse/movie/activity/moviedetail/DateSpinnerListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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<*>?) { | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
app/src/main/java/woowacourse/movie/activity/moviedetail/MovieDetailActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
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" | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
app/src/main/java/woowacourse/movie/activity/moviedetail/MovieDetailView.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
|
||
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) | ||
} | ||
} |
107 changes: 107 additions & 0 deletions
107
app/src/main/java/woowacourse/movie/activity/moviedetail/ReservationInfoView.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
|
||
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 | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
app/src/main/java/woowacourse/movie/activity/movielist/MovieListActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
) | ||
listView.adapter = adapter | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
app/src/main/java/woowacourse/movie/activity/movielist/MovieListAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
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) | ||
} | ||
} | ||
} |
Oops, something went wrong.