➢Tiếp tục phát triển sang hệ điều hành IOS.
➢Tối ưu hóa quá trình truyền tải và hiển thị, giảm thời gian tải dữ liệu từ máy chủ Firebase về hệ thống.
Tài liệu tham khảo
Tiếng Việt:
1. Tran Van Canh. Scan QR/Barcode với ZXing Android Embedded (journeyapps/zxing-
android-embedded) trong Android, 19/12/2020, https://viblo.asia/p/scan-qrbarcode-voi-zxing- android-embedded-journeyappszxing-android-embedded-trong-android-924lJqWWZPM
2. Thắng Cảnh. Dân số thành phố Vũng Tàu là 351.300 người với
101.347 hộ,
15/12/2020,http://vungtau.baria-vungtau.gov.vn/web/guest/tin-
tuc/- /brvt/extAssetPublisher/content/8857902/dan-so-thanh-pho-vung-tau-la-351- 300-nguoi-voi- 101-347-ho
3. Nguyen Minh Duong. Tạo ứng dụng QR code Scanner nhanh chóng với thư viện ZXING,
19/12/2020,https://viblo.asia/p/tao-ung-dung-qr-code-scanner-nhanh-chong-voi-thu- vien- zxing-ORNZqPp3K0n
4. Đỗ Đức Đình Đạt. Firebase là gì? Giải pháp lập trình không cần Backend từ
Google, 18/12/2020,https://wiki.matbao.net/firebase-la-gi-giai-phap-lap-trinh-khong-can- backend-tu- google/#firebase-la-gi 5. Anroid (hệ điều hành), 16/12/2020, https://vi.wikipedia.org/wiki/Android_(h%E1%BB%87_%C4%91i%E1%BB%81u_h%C3% A0nh) 6. Kotlin (ngôn ngữ lập trình), 16/12/2020, https://vi.wikipedia.org/wiki/Kotlin_(programming_language)
7. Vũ Hoàng Lâm Nhi (2020), Xây dựng hệ thống quản lý bảo dưỡng, sửa chữa thiết
bị cho doanh nghiệp – IziSolution, Đồ án, trường Đại Học Bà Rịa Vũng Tàu, Vũng Tàu
8. Nguyễn Mạnh Quân. Cùng tìm hiểu về Kotlin (Phần 1), 16/12/2020,
https://viblo.asia/p/cung-tim-hieu-ve-kotlin-phan-2-924lJMDXZPM 9. Nguyễn Ngọc Trung. Kotlin và Java: kế thừa và phát triển, 17/12/2020, https://codecungtrung.com/kotlin/kotlin-va-java/ 10. Trần Duy Trưởng. Tổng quan về Kotlin, 17/12/2020, https://labs.septeni- technology.jp/android-2/tong-quan-ve-kotlin/ 11. David Xuân. Giới thiệu mọi thứ về Firebase của Google, 18/12/2020,
12. Nguyen Thi Tu Yen. MPAndroidChart and Example, 20/12/2020,
https://viblo.asia/p/mpandroidchart-and-example-Az45badzlxY Tiếng Anh:
1. Rkistner. ZXing Android Embedded, 19/12/2020,
https://github.com/journeyapps/zxing- android-embedded
2. Philipp Jahoda. MPAndroidChart, 20/12/2020,
Phụ lục
Phụ lục A. Cấu trúc ứng dụng Motel Management
Hình phụ lục 1. Cấu trúc chung của ứng dụng Motel Management
Bảng phụ lục 1. Bảng mô tả cấu trúc thư mục con của hình phụ lục 2 STT Tên thư mục 1 adapters 2 anim 3 common 4 event 5 firebase 6 fragment 7 models 8 motelroomtt 9 others 10 view
Code của class BillAdapter, các class CartAdapter, LodgerAdapter, RoomAdapter, ServiceAdapter, ChooseImageServiceAdapter xử lý tương tự:
class BillAdapter(var listBill: ArrayList<Bill>):
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object{
const val SECTION_VIEW = 0
const val CONTENT_VIEW = 1
const val LOADING_VIEW = -1
}
public var isAll=false private var mValid = true
private val mSections: SparseArray<Section> = SparseArray<Section>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder
{
return if (viewType === LOADING_VIEW) { LoadingViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_load_more, parent, false) )
} else {
if (viewType === SECTION_VIEW ) { SectionHeaderViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_header_rv_bill, parent, false) )
} else ItemViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_rv_bill, parent,
false),
parent.context
) } }
fun addItems(listBillNew: ArrayList<Bill>){
listBill.addAll(listBillNew) notifyDataSetChanged() }
override fun getItemViewType(position: Int): Int {
return if (listBill[position].id.isEmpty()) {
LOADING_VIEW
} else {
if (listBill[position]._isSection) {
SECTION_VIEW } else { CONTENT_VIEW } } } fun addLoading(){ listBill.add(Bill())
notifyItemInserted(listBill.size - 1) }
fun removeLoading() {
if (listBill.size==0){
return
}
val position: Int = listBill.size - 1
val item: Bill = getItem(position)
if (item != null&&item.id.isEmpty()) {
listBill.removeAt(position) notifyItemRemoved(position) }
}
private fun getItem(position: Int): Bill {
return listBill[position] }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { if
(SECTION_VIEW == getItemViewType(position)) {
SectionHeaderViewHolder
val sectionItem: Bill = listBill[position]
val date:String=MyString.convertLongToTime(sectionItem.createDateBill, "MM/yyyy")
sectionHeaderViewHolder.txtMonthBill.text ="Month ".plus(date)
var total:Double =0.0
var count:Int=0
val listBillAll= if(!isAll) {
SplashScreenActivity.listBills.filter{ p->p.roomId==sectionItem.roomId} }
else{
SplashScreenActivity.listBills
}
for (bill:Bill in listBillAll ){
val dateBill:String=MyString.convertLongToTime(bill.createDateBill, "MM/yyyy")
if (!bill._isSection && dateBill == date){
total+=bill.total count++ }
}
sectionHeaderViewHolder.txtTotal.text = MyString.convertNumberFormat("%,.0f",
total).plus(
"đ" )
sectionHeaderViewHolder.txtTotalBill.text=MyString.convertNumberFormat("%,d",
count).plus( " bill" ) return } if (LOADING_VIEW == getItemViewType(position)) { return }
val itemViewHolder:ItemViewHolder = holder as ItemViewHolder val currentBill: Bill = listBill[position]
val room:Room = (SplashScreenActivity.listRooms.filter{ p->p.id ==currentBill.roomId
})[0]
itemViewHolder.txtBillName.text = currentBill.billName itemViewHolder.txtRoomName.text = room.roomName
itemViewHolder.txtCreateDateBill.text = MyString.convertLongToTime(
currentBill.createDateBill, "MM/yyyy HH:mm" )
if (currentBill.dateOfPayment==0L){
itemViewHolder.txtBillStatus.setTextColor(Color.RED)
itemViewHolder.txtBillStatus.text="Unpaid" }else{
itemViewHolder.txtBillStatus.setTextColor(Color.BLACK)
itemViewHolder.txtBillStatus.text="Paid" }
val totalBill:ArrayList<DetailBill> = SplashScreenActivity.listDetailBills.filter{ p- >p.billId==currentBill.id} as ArrayList<DetailBill>
if (totalBill.size==1){
val context=itemViewHolder.itemView.context
val service: Service = ( SplashScreenActivity.listServices.filter
>p.id==totalBill[0].serviceId })[0]
val uri:String = "@drawable/".plus(service.imageName)
(without the extension) is the file
var imageResource:Int = context.resources.getIdentifier(uri, null context.packageName)
val res: Drawable = context.resources.getDrawable(imageResource itemViewHolder.imgIconBill.setImageDrawable(res)
}else{
itemViewHolder.imgIconBill.setImageResource(R.drawable.ic_bill
}
itemViewHolder.txtTotalBill.text=MyString.convertNumberFormat("%,.0f"
currentBill.total).plus( "đ" )
itemViewHolder.itemView.setOnClickListener {
var intent=Intent(itemViewHolder.itemView.context, DetailBillActivity intent.putExtra("BillSelected", currentBill)
itemViewHolder.itemView.context.startActivity(intent)
itemViewHolder.itemView.setOnLongClickListener {
/ f.onBind()
f.show(
(it?.context as FragmentActivity).supportFragmentManager, f.tag
)
true
}
}
private fun getTotalMonth (date: String): Double {
var total:Double=0.0
for (bill:Bill in listBill){
val dateBill:String=MyString.convertLongToTime(bill.createDateBill, "MM/yyyy")
if (!bill._isSection && dateBill == date){
total+=bill.total
} }
return total
}
override fun getItemCount(): Int {
return listBill.size
}
fun clear() {
listBill.clear()
notifyDataSetChanged() }
class LoadingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var progressBar: ProgressBar init {
progressBar=itemView.findViewById(R.id.progressBar) }
}
class ItemViewHolder(itemView: View, context: Context?) :
RecyclerView.ViewHolder(itemView) {
var txtBillName: TextView var txtCreateDateBill:TextView var txtBillStatus:TextView var txtTotalBill:TextView var txtRoomName:TextView var imgIconBill:ImageView init {
txtBillName = itemView.findViewById(R.id.txtBillName)
txtCreateDateBill = itemView.findViewById(R.id.txtCreateDateBill)
txtBillStatus = itemView.findViewById(R.id.txtBillStatus )
txtTotalBill = itemView.findViewById(R.id.txtTotalBill )
txtRoomName = itemView.findViewById(R.id.txtRoomName)
imgIconBill = itemView.findViewById(R.id.imgIconBill) }
}
class SectionHeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var txtMonthBill: TextView var txtTotal:TextView var txtTotalBill:TextView init {
txtMonthBill = itemView.findViewById(R.id.txtMonthBill)
txtTotal = itemView.findViewById(R.id.txtTotal)
txtTotalBill = itemView.findViewById(R.id.txtTotalBill) }
}
class Section(var firstPosition: Int, var title: CharSequence) { var sectionedPosition = 0
} }
Hình phụ lục 4. Cấu trúc thư mục anim
Trong thư mục này gồm có hai class BaseViewAnimator, ZoomInDownAnimator. Hai class này có ý nghĩa lần lượt là class trừu tượng hiệu ứng, class còn lại là class định nghĩa hiệu ứng.
Code trong class BaseViewAnimator như sau:
abstract class BaseViewAnimator {
val DURATION: Long = 1000
private var mAnimatorSet: AnimatorSet? = null private var mDuration = DURATION
private var mRepeatTimes = 0
private var mRepeatMode = ValueAnimator.RESTART
init {
mAnimatorSet = AnimatorSet() }
protected abstract fun prepare(target: View)
open fun setTarget (target: View): BaseViewAnimator? { reset(target)
prepare(target)
return this
}
open fun animate() { start()
}
open fun restart() {
mAnimatorSet = mAnimatorSet!!.clone() start()
}
/**
* reset the view to default status
*
* @param target
*/
open fun reset(target: View?) {
ViewCompat.setAlpha(target, 1f) ViewCompat.setScaleX(target, 1f) ViewCompat.setScaleY(target, 1f) ViewCompat.setTranslationX(target, 0f) ViewCompat.setTranslationY(target, 0f) ViewCompat.setRotation(target, 0f) ViewCompat.setRotationY(target, 0f) ViewCompat.setRotationX(target, 0f) } /** * start to animate */
for (animator in mAnimatorSet!!.childAnimations) {
if (animator is ValueAnimator) {
animator.repeatCount = mRepeatTimes animator.repeatMode = mRepeatMode
} }
mAnimatorSet!!.duration = mDuration mAnimatorSet!!.start()
}
open fun setDuration(duration: Long): BaseViewAnimator? {
mDuration = duration
return this
}
open fun setStartDelay(delay: Long): BaseViewAnimator? { getAnimatorAgent()!!.startDelay = delay
return this
}
open fun getStartDelay(): Long {
return mAnimatorSet!!.startDelay
}
open fun addAnimatorListener(l: Animator.AnimatorListener?): BaseViewAnimator? {
mAnimatorSet !!.addListener(l)
return this
}
open fun cancel() {
mAnimatorSet!!.cancel() }
open fun isRunning(): Boolean {
return mAnimatorSet!!.isRunning
}
open fun isStarted(): Boolean {
return mAnimatorSet!!.isStarted
}
open fun removeAnimatorListener(l: Animator.AnimatorListener) {
mAnimatorSet!!.removeListener(l) }
open fun removeAllListener() {
mAnimatorSet!!.removeAllListeners() }
open fun setInterpolator(interpolator: Interpolator): BaseViewAnimator {
mAnimatorSet !!.interpolator = interpolator
return this
}
open fun getDuration(): Long {
return mDuration
}
open fun getAnimatorAgent (): AnimatorSet {
return mAnimatorSet!! }
open fun setRepeatTimes(repeatTimes: Int): BaseViewAnimator {
mRepeatTimes = repeatTimes
return this
}
open fun setRepeatMode(repeatMode: Int): BaseViewAnimator {
mRepeatMode = repeatMode
return this
} }
Code trong class ZoomInDownAnimator như sau:
class ZoomInDownAnimator: BaseViewAnimator() {
override fun prepare(target: View) { getAnimatorAgent().playTogether(
ObjectAnimator.ofFloat(target, "scaleX", 0.1f, 0.475f,1.0f),
ObjectAnimator.ofFloat(target, "scaleY", 0.1f, 0.475f,1.0f),
ObjectAnimator.ofFloat(target, "translationY", -target.bottom*1.0f, 60*1.0f,0f),
ObjectAnimator.ofFloat(target, "alpha", 0.0f, 1.0f, 1.0f) );
} }
Hình phụ lục 5. Cấu trúc của thư mục common
Code của class ValidationHelpers – có chức năng kiểm tra dữ liệu đầu vào:
const valEMAIL_REGEX = "(?:[a-z0-9!#\$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#\$%&'*+/=?^_`{|}~- ]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-
\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9- ]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0- 9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53- \\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
const valMIN_CREDENTIAL_LENGTH = 6
const valMIN_JOKE_LENGTH = 10
fun isEmailValid(email: String) = Pattern.matches(EMAIL_REGEX, email)
fun isPasswordValid(password: String) = password.length >=MIN_CREDENTIAL_LENGTH
fun isUsernameValid(username: String) = username.length >=MIN_CREDENTIAL_LENGTH
fun arePasswordsSame(password: String, repeatPassword: String) =isPasswordValid(password) &&
isPasswordValid(repeatPassword) && password == repeatPassword
fun isValidJoke(jokeText: String) = jokeText.length >= MIN_JOKE_LENGTH
Hình phụ lục 6. Cấu trúc thư mục event
Code của Class PaginationListener:
abstract class PaginationListener (private val layoutManager: LinearLayoutManager):
RecyclerView.OnScrollListener() {
companion object{
const val PAGE_START = 1
const val PAGE_SIZE = 10
}
/**
* Set scrolling threshold here (for now i'm assuming 10 item in one page) */
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState) }
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy)
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
if (!isLoading() && !isLastPage()) {
if (visibleItemCount + firstVisibleItemPosition >= totalItemCount &&
firstVisibleItemPosition >= 0 && totalItemCount >= PAGE_SIZE) {
loadMoreItems() }
} }
protected abstract fun loadMoreItems()
abstract fun isLastPage(): Boolean abstract fun isLoading(): Boolean
}
Hình phụ lục 7. Cấu trúc của thư mục fragment
Code của class BottomSheetInfoBill, class BottomSheetInfoRoom xử lý tương tự:
class BottomSheetInfoBill(val data: Bill): BottomSheetDialogFragment() {
private lateinit var txtRoomName: TextView private lateinit var txtDescription: TextView private lateinit var txtTimeCreate: TextView private lateinit var txtTimePaid: TextView private lateinit var txtTotalBill: TextView private lateinit var txtBillStatus: TextView private lateinit var imgIconBill:ImageView private lateinit var btnPayment:Button private lateinit var btnClose:Button override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? {
val view:View=inflater.inflate(R.layout.bottom_sheet_info_bill, container, false)
txtRoomName=view.findViewById(R.id.txtRoomName)
txtDescription=view.findViewById(R.id.txtDescription )
txtTimeCreate=view.findViewById(R.id.txtTimeCreate)
txtTimePaid=view.findViewById(R.id.txtTimePaid)
txtTotalBill=view.findViewById(R.id.txtTotalBill)
txtBillStatus=view.findViewById(R.id.txtBillStatus)
imgIconBill=view.findViewById(R.id.imgIconBill)
btnPayment=view.findViewById(R.id.btnPayment)
btnClose=view.findViewById(R.id.btnClose)
return view
}
override fun getTheme(): Int = R.style.BottomSheetDialog
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState)addControls()
addEvents() }
private fun addControls() {
if (data.id.isNotEmpty()){
val roomOfBill:Room=SplashScreenActivity.listRooms.filter{ p->p.id==data.roomId
}[0]
txtRoomName.text=roomOfBill.roomName if (data.description.isNotEmpty()){
txtDescription.text=data.description
}
txtTimeCreate.text= MyString.convertLongToTime(data.createDateBill,"dd-MM-yyyy HH:mm")
if (data.dateOfPayment!=0L){
txtTimePaid.text= MyString.convertLongToTime(data.createDateBill,"dd-MM-yyyy HH:mm")
}else{
txtBillStatus.text="Unpaid"
txtBillStatus.setTextColor(resources.getColor(R.color.colorRed))
btnPayment.visibility=View.VISIBLE
}
txtTotalBill.text=MyString.convertNumberFormat("%,.0f", data.total).plus("đ" )
val totalBill:ArrayList<DetailBill> = SplashScreenActivity.listDetailBills.filter
{ p->p.billId==data.id} as ArrayList<DetailBill> if
(context!=null){
if (totalBill.size==1){
val service: Service = (SplashScreenActivity.listServices.filter{ p- >p.id==totalBill[0].serviceId})[0]
val uri:String = "@drawable/".plus(service.imageName)// where myresource (without the extension) is the file
var imageResource:Int = requireContext().resources.getIdentifier(uri, null, requireContext().packageName)
val res: Drawable = requireContext().resources.getDrawable(imageResource,
null)
imgIconBill.setImageDrawable(res) }else{
imgIconBill.setImageResource(R.drawable.ic_bill) }
} } }
private fun addEvents() {
btnClose.setOnClickListener {
dialog?.dismiss()
}
btnPayment.setOnClickListener {
if (data.dateOfPayment!=0L||data.id.isEmpty()){
return@setOnClickListener
}
var database:DatabaseReference= Firebase.database.reference val
dateOfPayment:Long= Calendar .getInstance().timeInMillis
data.dateOfPayment=dateOfPayment
val myRef: DatabaseReference = database.child(Configs.TableName_Bill)
myRef.child(data.id).setValue(data).addOnCompleteListener {task->
if (task.isSuccessful){
dialog?.dismiss()
Toast.makeText(it.context,"Payment Successful!!",Toast.LENGTH_LONG ).show()
/* Snackbar.make(it, "Payment Successful!!", Snackbar.LENGTH_LONG) .setAction("Action", null).show()*/
}else{
dialog?.dismiss()
Toast.makeText(it.context,"Payment fail!!",Toast.LENGTH_LONG ).show()
/*Snackbar.make(it, "Payment fail!!", Snackbar.LENGTH_LONG) .setAction("Action", null).show()*/
}
} }
Code của class HomeFragment, class ListBillFragment, ListLodgerFragment, ReportFragment xử lý tương tự:
class HomeFragment : Fragment() {
/ TODO: Rename and change types of parameters private var param1: String? = null private var param2: String? = null
private lateinit var roomSelected: Room
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
arguments?.let{
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
/ Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false) }
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState)
(requireActivity() as AppCompatActivity).supportActionBar?.hide() addControls()
addEvents() }
private fun addEvents() {
btnGenerateQRCode.setOnClickListener {
startActivity(Intent(activity, GenerateQrCodeActivity::class.java))
}
imgEditRoom.setOnClickListener {
val intent:Intent=Intent(activity, RoomActivity::class.java)
intent.putExtra("RoomSelected", InfoRoomActivity.roomSelected) startActivity(intent)
}
btnAddLodger.setOnClickListener {
val intent:Intent=Intent(activity, LodgerActivity::class.java) startActivity(intent)
}
btnConfirmCheckOut.setOnClickListener {
val totalBillUnpaid:Int=(SplashScreenActivity .listBills.filter{ p- >(p.roomId==roomSelected.id&&p.dateOfPayment==0L) }).size
if (totalBillUnpaid>0){
val builder = AlertDialog.Builder(context)
builder.setTitle("Error!")
builder.setMessage("Please payment all bill(unpaid)!")
builder.setPositiveButton("Go to payment",
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss()
val intent: Intent = Intent(context, BillActivity::class.java)
intent.putExtra("RoomSelected", InfoRoomActivity.roomSelected) startActivity(intent)
})
builder.setNegativeButton("No",
DialogInterface.OnClickListener { dialog, which -> dialog.dismiss() })
builder.create().show()
return@setOnClickListener
}
InfoRoomActivity.roomSelected.isFull=false val myRef2: DatabaseReference =
Firebase.database.reference.child(Configs.TableName_Room)
myRef2.child(InfoRoomActivity.roomSelected.id).setValue(InfoRoomActivity.roomSelected).addOnCo mpleteListener { task ->
if (task.isSuccessful) {
Toast.makeText(activity, "Room status is empty", Toast.LENGTH_LONG).show() }
}
val listLodger:ArrayList<Lodger> = SplashScreenActivity.listLodgers.filter{ p- >p.roomId==InfoRoomActivity.roomSelected.id} as ArrayList<Lodger>
for (lodger:Lodger in listLodger){
val myRef3: DatabaseReference =
Firebase.database.reference.child(Configs.TableName_Lodger)
lodger.roomId=""
myRef3.child(lodger.id).setValue(lodger) }
val ft: FragmentTransaction = requireFragmentManager().beginTransaction()
ft.detach(this).attach(this).commit()
}
}
private fun addControls() {
roomSelected = if (InfoRoomActivity.roomSelected!=null){
InfoRoomActivity.roomSelected
}else{ Room() }
txtRoomName.text=roomSelected.roomName
txtRoomRate.text=
MyString.Companion.convertNumberFormat("%,d",
roomSelected.roomRate).plus( " đ"
)
startCountAnimation(txtElectricityIndex, 0, roomSelected.electricityIndex) startCountAnimation(txtWaterIndex, 0, roomSelected.waterIndex)
/*txtElectricityIndex.text=roomSelected.electricityIndex.toString() txtWaterIndex.text=roomSelected.waterIndex.toString()*/
if (!roomSelected.isFull){
txtRoomStatus.text= "Empty"
/ imgIconRoom.setImageResource(R.drawable.ic_room_empty)
btnConfirmCheckOut.visibility=View.GONE
btnAddLodger.visibility=View.VISIBLE
}
val totalLodger:Int=(SplashScreenActivity.listLodgers.filter{ p- >p.roomId==roomSelected.id}).size
startCountAnimation(txtTotalLodger, 0, totalLodger)
val totalBill:Int=(SplashScreenActivity.listBills.filter{ p- >p.roomId==roomSelected.id}).size
startCountAnimation(txtTotalBill, 0, totalBill) txtRoomId.text=roomSelected.id
val totalBillUnpaid:Int=(SplashScreenActivity.listBills.filter{ p- >(p.roomId==roomSelected.id&&p.dateOfPayment==0L) }).size
startCountAnimation(txtTotalBillUnPaid, 0, totalBillUnpaid) }
private fun startCountAnimation( view: TextView,
numberStart: Int = 0, numberEnd: Int = 600, duration: Long = 1000L
) {
val animator = ValueAnimator.ofInt(numberStart, numberEnd)//0 is min number, 600 is max number
animator.duration = duration //Duration is in milliseconds animator.addUpdateListener { animation -> view.text =
animation.animatedValue.toString() }
animator.start() }
companion object {
/**
/ TODO: Rename and change types and number of parameters @JvmStatic
fun newInstance(param1: String, param2: String) = HomeFragment().apply{
arguments = Bundle().apply
{ putString(ARG_PARAM1, param1) putString(ARG_PARAM2, param2) } } } }
Bảng phụ lục 2. Bảng mô tả cấu trúc thư mục con của hình phụ lục 8 STT Tên Class 1 Bill 2 DetailBill 3 DetailRoom 4 Lodger 5 Room 6 Service
Code của class Bill, các class DetailBill, DetailRoom, Lodger, Room, Service xử lý tương
tự:
class Bill:Serializable {
private var _id:String=""
private var _billName:String=""
private var _createDateBill:Long = 0
private var _dateOfPayment:Long =0
private var _total:Double=0.0
private var _roomId:String=""
var _isSection:Boolean=false private var _description:String=""
constructor(){}
constructor(_id: String,_billName:String, _createDateBill: Long, _dateOfPayment: Long, _roomId: String,_isSection:Boolean=false,_total:Double, _description:String="") {
this._id = _id
this._billName = _billName
this._createDateBill = _createDateBill
this._dateOfPayment = _dateOfPayment
this._roomId = _roomId
this._isSection=_isSection
this._total=_total
this._description=_description } var id:String get() { return _id } set(value) {
this._id=value }
var billName:String get() {
return _billName
}
set(value) {
this._billName=value }
var description:String get() {
return _description
}
set(value) {
this._description=value }
var createDateBill: Long get() {
return _createDateBill
}
set(value) {
this._createDateBill=value }
var total: Double get() {
return _total
}
set(value) {
this._total=value }
var dateOfPayment: Long get() {
return _dateOfPayment
}
set(value) {
this._dateOfPayment=value }
var roomId: String get() {
return _roomId
}
set(value) {
}
override fun toString(): String {
return this._billName
}
fun copy(bill:Bill, _isSection:Boolean=false):Bill{
return
Bill(bill.id,bill.billName,bill.createDateBill,bill.dateOfPayment,bill.roomId,_isSection,bill. total
,bill.description) }
}
Bảng phụ lục 3. Bảng mô tả cấu trúc thư mục con của hình phụ lục 9 STT Tên Class 1 AddBillActivity 2 AddDetailBill 3 AddServiceActivity 4 BillActivity 5 DashBoardActivity 6 DetailBillActivity 7 DetailLodgerActivity 8 GenerateQrCodeActivity 9 InfoRoomActivity 10 LodgerActivity 11 LoginActivity 12 MainActivity 13 ProfileActivity 14 RegisterActivity 15 ReportActivity 16 ResetPasswordActivity 17 RoomActivity 18 ServiceActivity 19 SplashScreenActivity 20 WriteIndexActivity
Phụ lục B. Cấu trúc ứng dụng Search Motel Information
Hình phụ lục 10. Cấu trúc chung của ứng dụng Search Motel Information
Hình phụ lục 11. Cấu trúc thư mục com.thanhtrung Bảng phụ lục 4. Bảng mô tả cấu trúc thư mục con của hình phụ lục 11
1 adapters 2 common 3 event 4 fragment 5 models 6 motelroomttlodger 7 os 8 others 9 view
Hình phụ lục 12. Cấu trúc của thư mục adapters
Hình phụ lục 14. Cấu trúc của thư mục models
Hình phụ lục 15. Cấu trúc thư mục motelroomttlodger