https://github.com/lnjky/fashion_people
GitHub - lnjky/fashion_people: 패션 추천 어플
패션 추천 어플. Contribute to lnjky/fashion_people development by creating an account on GitHub.
github.com
코드 전체를 보려면 위에 링크를 통해 확인할 수 있습니다.
이전의 글을 참고하면 좋습니다.
[안드로이드] 파이어베이스로 피드만들기 - 1
https://github.com/lnjky/fashion_people GitHub - lnjky/fashion_people: 패션 추천 어플 패션 추천 어플. Contribute to lnjky/fashion_people development by creating an account on GitHub. github.com 코드 전체를 보려면 위에 링크를 통해
loasd.tistory.com
[안드로이드] 파이어베이스로 피드 만들기 - 2
https://github.com/lnjky/fashion_people GitHub - lnjky/fashion_people: 패션 추천 어플 패션 추천 어플. Contribute to lnjky/fashion_people development by creating an account on GitHub. github.com 코드 전체를 보려면 위에 링크를 통해
loasd.tistory.com
피드를 완성했다.
주요한 기능인 사진 업로드와 코멘트 추가 기능을 만들었다.
그런데 아직 완성이 되자 않은게 초기의 목표가 사진을 올리고 평가받는 어플을 만들려 했기 때문에 별점기능을 추가해야 한다.
그래서 별점을 주기 위해 RatingBar 기능을 사용하였다.
RatingBar에 대한 내용은 아래의 링크를 통해 확인 가능하다.
[안드로이드] 별점 추가하기 ( XML )
https://github.com/lnjky/fashion_people GitHub - lnjky/fashion_people: 패션 추천 어플 패션 추천 어플. Contribute to lnjky/fashion_people development by creating an account on GitHub. github.com 코드 전체를 보려면 위에 링크를 통해
loasd.tistory.com
이전 글을 보면 알다시피 초기의 점수들을 이렇게 설정해주었다.
data.put("TOTAL_SCORE", 0);
data.put(FirebaseID.ratingcount, 1);
data.put(FirebaseID.rating, 0.0F);
총 점수 = 0 / 점수를 부여한 횟수 = 1 / 별점 = 0.0

이렇게 파이어스토어에 저장이 된다.
rating : 0
ratingcount : 1
TOTAL_SCORE : 0
으로 제대로 저장된 것을 확인할 수 있다.
이렇게 설정해둔 것은 리사이클러뷰에 정확한 수치를 띄우기 위해서이다.
이미지에 대한 점수를 스토어에 같이 저장해주고 변수들을 통해 계산해서 별점을 보여줘야 하기 때문이다.
우선 이미지를 스토리지에 업로드하면서 기본적인 세팅을 해줬기 때문에 추가로 XML을 만들고 별점을 부여하면 된다.
XML은 깔끔하게 이렇게 만들었다.

별점을 드래그를 통해 부여하고 현재 부여한 별점을 아래에 표기되게 하였고 완료버튼을 누르면 별점부여가 완료된다.
XML은 다음과 같다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PopupActivity">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar">
</include>
<ImageView
android:id="@+id/iv_popup_back"
android:layout_width="40dp"
android:layout_height="33dp"
android:background="@drawable/ic_baseline_arrow_back_24"
app:layout_constraintBottom_toBottomOf="@+id/toolbar"
app:layout_constraintEnd_toStartOf="@+id/tv_popup_title"
app:layout_constraintHorizontal_bias="0.064"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/toolbar"
app:layout_constraintVertical_bias="0.481">
</ImageView>
<TextView
android:id="@+id/tv_popup_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/koreanah1_r"
android:text="별점 주기"
android:textColor="@color/white"
android:textSize="25dp"
app:layout_constraintBottom_toBottomOf="@+id/toolbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/toolbar" />
<RatingBar
android:id="@+id/popup_ratingbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:isIndicator="false"
android:max="5"
android:progressTint="#B388FF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.419">
</RatingBar>
<TextView
android:id="@+id/popup_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="별점 : "
android:textColor="@color/black"
android:textSize="24dp"
app:layout_constraintEnd_toStartOf="@+id/popup_starpoint"
app:layout_constraintHorizontal_bias="0.718"
app:layout_constraintStart_toStartOf="@+id/popup_ratingbar"
app:layout_constraintTop_toBottomOf="@+id/popup_ratingbar">
</TextView>
<TextView
android:id="@+id/popup_starpoint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@color/black"
android:textSize="24dp"
app:layout_constraintEnd_toEndOf="@+id/popup_ratingbar"
app:layout_constraintHorizontal_bias="0.687"
app:layout_constraintStart_toStartOf="@+id/popup_ratingbar"
app:layout_constraintTop_toBottomOf="@+id/popup_ratingbar">
</TextView>
<Button
android:id="@+id/btn_shutdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/button_round"
android:onClick="shutDownClick"
android:text="완료"
android:textSize="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/popup_collectionid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/popup_ratingbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
</TextView>
<TextView
android:id="@+id/popup_documentid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/popup_collectionid"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
</TextView>
</androidx.constraintlayout.widget.ConstraintLayout>
android:isIndicator="false"
android:max="5"
isIndicator를 false로 주어 드래그하여 점수를 줄 수 있게 하였고
max를 5로 설정하여 최대 별점을 5점으로 설정하였다.
그렇다면 액티비티를 보도록 하자.
액티비티의 전체 코드는 다음과 같다.
package com.example.styleplt;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;
import android.widget.Toast;
import com.example.styleplt.utility.FirebaseID;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FieldValue;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.SetOptions;
import java.util.HashMap;
import java.util.Map;
public class PopupActivity extends AppCompatActivity {
private RatingBar popup_ratingbar;
private Button btn_shutdown;
private TextView popup_starpoint, popup_documentid, popup_collectionid;
private ImageView iv_popup_back;
private Intent intent;
private String documentid;
private String collectionid;
private String nickname;
private String current_documentID;
private String existingrating;
private String existingcount;
private String existingtotal;
private float totalrating;
private float totalscore;
private FirebaseFirestore mStore = FirebaseFirestore.getInstance();
private FirebaseAuth mAuth = FirebaseAuth.getInstance();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popup);
popup_ratingbar = findViewById(R.id.popup_ratingbar);
btn_shutdown = findViewById(R.id.btn_shutdown);
popup_starpoint = findViewById(R.id.popup_starpoint);
iv_popup_back = findViewById(R.id.iv_popup_back);
popup_documentid = findViewById(R.id.popup_documentid);
popup_collectionid = findViewById(R.id.popup_collectionid);
intent = getIntent();// 인텐트 받아오기
documentid = intent.getStringExtra("upload_documentID"); //Adapter에서 받은 키값 연결
collectionid = intent.getStringExtra("upload_collectionID");
popup_documentid.setText(documentid);
popup_collectionid.setText(collectionid);
// 뒤로가기
iv_popup_back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(); // 인텐트 객체 생성하고
setResult(RESULT_OK, intent); // 응답 보내기
finish(); // 현재 액티비티 없애기
}
});
//별점에 따라 숫자 표기
popup_ratingbar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
@Override
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
popup_starpoint.setText(String.valueOf(rating));
}
});
// 완료 클릭시
btn_shutdown.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Map<String, Object> data = new HashMap<>();
// data에 데이터 추가(삽입) -> 별점을 부여한 사람의 컬렉션 새로 생성
data.put(FirebaseID.documentId, mAuth.getCurrentUser().getUid());
data.put(FirebaseID.nickname, nickname); // 현재 사용중인 사용자의 닉네임
data.put(FirebaseID.timestamp, FieldValue.serverTimestamp()); // 서버 시간
data.put(FirebaseID.rating, popup_ratingbar.getRating());
mStore.collection(FirebaseID.upload).document(collectionid).collection(FirebaseID.uploadRating)
.document(documentid).set(data, SetOptions.merge());
// 점수 부여시 파이어스토어 db의 카운트가 1씩 증가
mStore.collection(FirebaseID.upload).document(collectionid).update("ratingcount",FieldValue.increment(1));
// 총 부여받은 점수 계산식 = 이전까지 받은 점수 + 별점을 통해 받은 점숫
totalscore = Float.parseFloat(existingtotal) + popup_ratingbar.getRating();
// 총 별점 = 총 부여받은 점수 / 총 부여한 횟수
totalrating = totalscore / Float.parseFloat(existingcount);
//위에 계산한 식대로 db의 정보 업데이트
mStore.collection(FirebaseID.upload).document(collectionid).update("TOTAL_SCORE", totalscore);
mStore.collection(FirebaseID.upload).document(collectionid).update(FirebaseID.rating, totalrating);
finish();
}
});
}
@Override
protected void onStart() {
super.onStart();
if (mAuth.getCurrentUser() != null) {
mStore.collection(FirebaseID.user).document(mAuth.getCurrentUser().getUid())
.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if(task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if(document.exists()) {
Log.d("TAG","Document is exists");
nickname = (String) document.getData().get(FirebaseID.nickname);
current_documentID = (String) document.getData().get(FirebaseID.documentId);
}
else
Log.d("TAG","Document is not exists");
}
}
});
}
// 기존의 별점 및 카운트 횟수 가져오기
mStore.collection(FirebaseID.upload).document(collectionid)
.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if(task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if(document.exists()) {
existingtotal = String.valueOf(document.getData().get("TOTAL_SCORE"));
existingrating = String.valueOf(document.getData().get(FirebaseID.rating));
existingcount = String.valueOf(document.getData().get(FirebaseID.ratingcount));
//Toast.makeText(getApplicationContext(), "rating : " + existingrating, Toast.LENGTH_SHORT).show();
//Toast.makeText(getApplicationContext(), "count : " + existingcount, Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(getApplicationContext(), "not document", Toast.LENGTH_SHORT).show();
}
}
});
}
}
하나하나 설명하자면 이렇다.
//별점에 따라 숫자 표기
popup_ratingbar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
@Override
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
popup_starpoint.setText(String.valueOf(rating));
}
});
별점을 표기하는 코드이다.
XML에서 만든 텍스트뷰에 현재 정해놓은 별점을 표기하게 해준다.
그리고 완료 버튼 클릭시 행동하는 코드이다.
// 완료 클릭시
btn_shutdown.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Map<String, Object> data = new HashMap<>();
// data에 데이터 추가(삽입) -> 별점을 부여한 사람의 컬렉션 새로 생성
data.put(FirebaseID.documentId, mAuth.getCurrentUser().getUid());
data.put(FirebaseID.nickname, nickname); // 현재 사용중인 사용자의 닉네임
data.put(FirebaseID.timestamp, FieldValue.serverTimestamp()); // 서버 시간
data.put(FirebaseID.rating, popup_ratingbar.getRating());
mStore.collection(FirebaseID.upload).document(collectionid).collection(FirebaseID.uploadRating)
.document(documentid).set(data, SetOptions.merge());
// 점수 부여시 파이어스토어 db의 카운트가 1씩 증가
mStore.collection(FirebaseID.upload).document(collectionid).update("ratingcount",FieldValue.increment(1));
// 총 부여받은 점수 계산식 = 이전까지 받은 점수 + 별점을 통해 받은 점숫
totalscore = Float.parseFloat(existingtotal) + popup_ratingbar.getRating();
// 총 별점 = 총 부여받은 점수 / 총 부여한 횟수
totalrating = totalscore / Float.parseFloat(existingcount);
//위에 계산한 식대로 db의 정보 업데이트
mStore.collection(FirebaseID.upload).document(collectionid).update("TOTAL_SCORE", totalscore);
mStore.collection(FirebaseID.upload).document(collectionid).update(FirebaseID.rating, totalrating);
}
});
데이터를 추가해주는 코드를 작성하였다.
Map<String, Object> data = new HashMap<>();
// data에 데이터 추가(삽입) -> 별점을 부여한 사람의 컬렉션 새로 생성
data.put(FirebaseID.documentId, mAuth.getCurrentUser().getUid());
data.put(FirebaseID.nickname, nickname); // 현재 사용중인 사용자의 닉네임
data.put(FirebaseID.timestamp, FieldValue.serverTimestamp()); // 서버 시간
data.put(FirebaseID.rating, popup_ratingbar.getRating());
mStore.collection(FirebaseID.upload).document(collectionid).collection(FirebaseID.uploadRating)
.document(documentid).set(data, SetOptions.merge());
이렇게 하면 upload - collectionid에 하위컬렉션 uploadRating이 생기고 별점을 준 사용자의 아이디, 부여한 점수 등이 새로 생길것이다.
그리고 .update()를 통해 데이터를 수정하게 하였다.
mStore.collection(FirebaseID.upload).document(collectionid).update("ratingcount",FieldValue.increment(1));
우선 파이어스토어에 저장되어있는 값을 점수를 줄 때마다 1씩 증가하게 한다.
그리고 완료 시점에서의 별점을 totalscore에 저장해준다.
totalscore = Float.parseFloat(existingtotal) + popup_ratingbar.getRating();
그러니까 지금까지 받은 별점의 총 합을 나타낸다.
그리고 별점의 총 합을 별점을 받은 횟수로 나눠준다.
totalrating = totalscore / Float.parseFloat(existingcount);
그리고 이렇게 계산된 변수들로 파이어스토어의 값을 수정해준다.
mStore.collection(FirebaseID.upload).document(collectionid).update("TOTAL_SCORE", totalscore);
mStore.collection(FirebaseID.upload).document(collectionid).update(FirebaseID.rating, totalrating);
이걸 사진을 통해 확인해보도록 하자.

별점이 0점일때의 모습이다.
색깔이 없고 회색별인 것을 확인할 수 있다.
이때의 파이어스토어의 모습은 이렇다.

각각의 필드값들의 상태는 이렇다.
rating : 0
ratingcount : 1
TOTAL_SCORE : 0
rating이 0이기 때문에 별점에 색이 들어오지 않는다.
그리고 별점을 부여해준다. 나는 5점을 부여해줬다.

그리고 별점이 부여된 모습이다.

별점이 이렇게 5점으로 꽉찼다.
그렇다면 파이어스토어의 모습은 어떨까

필드값들이 변경된 것을 확인할 수 있다.
rating : 5
ratingcount : 2
TOTAL_SCORE : 5
rating이 5점으로 변했기 때문에 별점이 5점까지 꽉 찬것을 확인할 수 있다.
그리고 여기서 별점을 3.5점 더 주면

좌측에 보면 필드값이 변한것을 확인할 수 있다.
rating : 4.25
ratingcount : 3
TOTAL_SCORE : 8.5
지금까지 부여받은 별점인 5 + 3.5 = 8.5로 TOTAL_SCORE에 저장되었고
ratingcount는 별점을 부여할때마다 1씩 증가하였다.
그리고 rating이 4.25점이 되어 표시되는 별점에도 영향을 준 것을 확인할 수 있다.
추가로 5점을 줬을때는 새로고침이 제대로 안되서 캡처를 못했는데 이렇게 document에 하위 컬렉션 "uploadRating"을 생성해주었다.
그리고 점수를 부여한 사용자의 데이터와 몇점을 부여했는지를 볼 수 있게 해주었다.

여기까지 피드에 별점을 부여하는 기능을 추가하는 방법을 작성해보았다.
아이템에 현재 별점을 보여주게 하는 기능을 추가하면 더 좋을 것 같다.
'안드로이드' 카테고리의 다른 글
| [안드로이드] 파이어베이스로 찜목록 만들기 (0) | 2023.01.12 |
|---|---|
| [안드로이드] 파이어베이스로 찜하기 만들기 (0) | 2023.01.12 |
| [안드로이드] 파이어베이스로 피드 만들기 - 2 (0) | 2023.01.11 |
| [안드로이드] 파이어베이스로 피드만들기 - 1 (0) | 2023.01.11 |
| [안드로이드] 파이어베이스 스토리지에 사진 올리기 (0) | 2023.01.10 |