안드로이드

[안드로이드] 파이어베이스로 피드만들기 - 1

loasd 2023. 1. 11. 00:18
반응형

https://github.com/lnjky/fashion_people

 

GitHub - lnjky/fashion_people: 패션 추천 어플

패션 추천 어플. Contribute to lnjky/fashion_people development by creating an account on GitHub.

github.com

코드 전체를 보려면 위에 링크를 통해 확인할 수 있습니다.


사진 업로드에 대해서는 아래의 링크를 통해 확인할 수 있습니다.

https://loasd.tistory.com/78

 

[안드로이드] 파이어베이스 스토리지에 사진 올리기

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


위의 링크를 통해 사진 업로드 기능을 완성했다면 이제 피드를 만들어보려 한다.

피드는 페이스북이나 인스타그램처럼 사진을 쓱 내려가면서 보거나 댓글을 다는 것을 말한다.

간단하게 사진, 사진에 대한 코멘트를 입력받는 기능과 이를 리사이클러뷰를 통해 확인하는 기능을 만들어보려 한다.

우선 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:background="#eeeeee"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_home_weather"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:background="#3E6BDA"
        android:gravity="center"
        android:text="오늘의 날씨"
        android:textColor="@color/white"
        android:textSize="24dp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0">

    </TextView>

    <ImageView
        android:layout_width="52dp"
        android:layout_height="55dp"
        android:background="@drawable/icon_weather_news_64"
        app:layout_constraintBottom_toBottomOf="@+id/tv_home_weather"
        app:layout_constraintEnd_toEndOf="@+id/tv_home_weather"
        app:layout_constraintHorizontal_bias="0.922"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.466">

    </ImageView>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/home_RecyclerView"
        android:layout_width="400dp"
        android:layout_height="647dp"
        android:layout_marginTop="3dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.454"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_home_weather"
        app:layout_constraintVertical_bias="0.0">

    </androidx.recyclerview.widget.RecyclerView>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/board_write"
        android:layout_width="wrap_content"
        android:layout_height="103dp"
        android:layout_alignParentEnd="true"
        android:layout_alignParentBottom="true"
        android:layout_marginEnd="30dp"
        android:layout_marginBottom="30dp"
        android:src="@drawable/ic_baseline_add_a_photo_24"
        app:backgroundTint="#B388FF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

    </com.google.android.material.floatingactionbutton.FloatingActionButton>

</androidx.constraintlayout.widget.ConstraintLayout>

 

XML을 만들었으니 이제 리사이클러뷰를 만들어보도록하자.

리사이클러뷰에 대한 자세한 설명은 아래의 링크를 통해 확인 가능하다.

https://loasd.tistory.com/62

 

[안드로이드] 리사이클러뷰 만들기

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

자세한 설명은 위의 링크를 통해 확인하고 여기서는 간단히 코드들만 정리하려 한다.

 

 1) UploadAdapter  < adapter >

package com.example.styleplt.adapter;

import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.LongDef;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;
import com.example.styleplt.MainActivity;
import com.example.styleplt.PopupActivity;
import com.example.styleplt.R;
import com.example.styleplt.SaveActivity;
import com.example.styleplt.UploadActivity;
import com.example.styleplt.fragment.HomeFragment;
import com.example.styleplt.models.Upload;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.FirebaseFirestore;

import java.util.List;

public class UploadAdapter extends RecyclerView.Adapter<UploadAdapter.UploadViewHolder>{

    private FirebaseFirestore mStore = FirebaseFirestore.getInstance();
    private FirebaseAuth mAuth = FirebaseAuth.getInstance();

    private List<Upload> datas;

    private String collectionid2;
    private Uri uri;

    public UploadAdapter(List<Upload> datas) {
        this.datas = datas;
    }

    @NonNull
    @Override
    public UploadViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new UploadViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_upload, parent, false));
    }


    @Override
    public void onBindViewHolder(@NonNull UploadViewHolder holder, int position) {
        Upload data = datas.get(position);
        holder.nickname.setText(data.getNickname());
        holder.contents.setText(data.getContents());
        holder.documentid.setText(data.getDocumentId());
        holder.collectionid.setText(data.getCollectionId());
        holder.upload_time.setText(data.getTimestamp());
        holder.upload_ratingbar.setRating(Float.parseFloat(data.getRating().toString()));
        holder.item_upload_url.setText(data.getUrl());
        Glide.with(holder.itemView)
                .load(datas.get(position).getImage())
                .into(holder.image);
    }

    @Override
    public int getItemCount() {
        return (datas != null ? datas.size() : 0);
    }

    class UploadViewHolder extends RecyclerView.ViewHolder {

        private TextView nickname;
        private TextView contents;
        private TextView tv_ratingbar;
        private TextView documentid;
        private TextView collectionid;
        private TextView upload_time;
        private TextView item_upload_url;
        private ImageView image;
        private RatingBar upload_ratingbar;
        private ImageView item_upload_star;
        private ImageView item_upload_delete;

        public UploadViewHolder(@NonNull View itemView) {
            super(itemView);

            nickname = itemView.findViewById(R.id.item_upload_nickname);
            contents = itemView.findViewById(R.id.item_upload_contents);
            image = itemView.findViewById(R.id. item_upload_image);
            tv_ratingbar = itemView.findViewById(R.id.tv_ratingbar);
            upload_ratingbar = itemView.findViewById(R.id.upload_ratingbar);
            documentid = itemView.findViewById(R.id.item_upload_documentid);
            collectionid = itemView.findViewById(R.id.item_upload_collectionid);
            upload_time = itemView.findViewById(R.id.upload_time);
            item_upload_star = itemView.findViewById(R.id.item_upload_star);
            item_upload_delete = itemView.findViewById(R.id.item_upload_delete);
            item_upload_url = itemView.findViewById(R.id.item_upload_url);

            // 별점주기 클릭시 화면 전환 및 docuemntid, collectionid popupactivity로 전송
            tv_ratingbar.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(view.getContext(), PopupActivity.class);
                    intent.putExtra("upload_documentID", documentid.getText().toString());
                    intent.putExtra("upload_collectionID", collectionid.getText().toString());
                    intent.putExtra("upload_rating", upload_ratingbar.getRating());

                    view.getContext().startActivity(intent);
                }
            });

            //
            item_upload_delete.setVisibility(View.INVISIBLE);

            item_upload_star.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(view.getContext(), SaveActivity.class);
                    Uri uri = Uri.parse(item_upload_url.getText().toString());
                    intent.putExtra("uri", uri); // contents:// 이렇게 나와서 이걸 url로 바꾸는 방법을 찾아내야 함
                    view.getContext().startActivity(intent);
                }
            });



        }
    }
}

뷰홀더를 통해 아이템을 넣어준다.

사진은 Glide를 통해 올라가게 하였고 ratingbar는 별점기능을 위해 사용할 것이기 때문에 추가해주었다.

그 외에 사진을 올린 사람, 시간 등 파이어스토어에서 구분하기 위해 여러 값들을 추가해주었다.

 

 2) Upload  < models>

package com.example.styleplt.models;

public class Upload {

    private String documentId;
    private String contents;
    private String nickname;
    private String image;
    private String collectionId;
    private String rating;
    private String timestamp;
    private String url;

    public Upload() {
    }

    public Upload(String documentId, String contents, String nickname, String image, String collectionId, String rating, String timestamp, String url) {
        this.documentId = documentId;
        this.contents = contents;
        this.nickname = nickname;
        this.image = image;
        this.collectionId = collectionId;
        this.rating = rating;
        this.timestamp = timestamp;
        this.url = url;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    public String getRating() {
        return rating;
    }

    public void setRating(String rating) {
        this.rating = rating;
    }

    public String getDocumentId() {
        return documentId;
    }

    public void setDocumentId(String documentId) {
        this.documentId = documentId;
    }

    public String getContents() {
        return contents;
    }

    public void setContents(String contents) {
        this.contents = contents;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }


    public String getCollectionId() {
        return collectionId;
    }

    public void setCollectionId(String collectionId) {
        this.collectionId = collectionId;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "Upload{" +
                "documentId='" + documentId + '\'' +
                ", contents='" + contents + '\'' +
                ", nickname='" + nickname + '\'' +
                ", image='" + image + '\'' +
                ", collectionId='" + collectionId + '\'' +
                ", rating='" + rating + '\'' +
                ", timestamp='" + timestamp + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
}

모델을 만드는 것은 어렵지 않다.

Alt + Insert를 통해 Constructor, Getter and Setter, toString()을 만들어 주면 된다.

 

 3) item_upload  < 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="wrap_content"
    android:background="@drawable/button_round"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/item_upload_image"
        android:layout_width="390dp"
        android:layout_height="wrap_content"

        android:layout_marginTop="7dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/item_upload_contents"
        app:layout_constraintTop_toBottomOf="@+id/upload_time">

    </ImageView>

    <TextView
        android:id="@+id/item_upload_contents"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:background="@drawable/button_round"
        android:gravity="center"
        android:text="contents"
        android:textColor="@color/black"
        android:textSize="23dp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/item_upload_image"
        app:layout_constraintVertical_bias="0.0"></TextView>

    <TextView
        android:id="@+id/item_upload_nickname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:text="nickname"
        android:textColor="@color/black"
        android:textSize="23dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.051"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </TextView>

    <RatingBar
        android:id="@+id/upload_ratingbar"
        style="@style/Widget.AppCompat.RatingBar.Indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="3dp"
        android:layout_marginBottom="4dp"
        android:isIndicator="true"
        android:max="5"
        android:rating="0"
        android:stepSize="0.5"
        android:progressTint="#B388FF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/tv_ratingbar"
        app:layout_constraintHorizontal_bias="0.48"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/item_upload_contents">

    </RatingBar>

    <TextView
        android:id="@+id/tv_ratingbar"
        android:layout_width="150dp"
        android:layout_height="25dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
        android:layout_marginBottom="5dp"
        android:background="@drawable/button_round"
        android:gravity="center"
        android:text="별점 주기"
        android:textColor="@color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/item_upload_contents"
        app:layout_constraintVertical_bias="0.0">

    </TextView>

    <TextView
        android:id="@+id/upload_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="25dp"
        android:text="time"
        android:textColor="@color/black"
        android:textSize="14dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/item_upload_nickname">

    </TextView>

    <TextView
        android:id="@+id/item_upload_ratingcount"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="32dp"
        android:visibility="invisible"
        app:layout_constraintEnd_toStartOf="@+id/item_upload_rating"
        app:layout_constraintTop_toTopOf="parent">

    </TextView>

    <TextView
        android:id="@+id/item_upload_documentid"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="148dp"
        android:visibility="invisible"
        app:layout_constraintEnd_toEndOf="parent"
        tools:layout_editor_absoluteY="1dp">

    </TextView>

    <TextView
        android:id="@+id/item_upload_collectionid"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="36dp"
        android:visibility="invisible"
        app:layout_constraintEnd_toStartOf="@+id/item_upload_documentid"
        app:layout_constraintTop_toTopOf="parent">

    </TextView>

    <TextView
        android:id="@+id/item_upload_rating"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="160dp"
        android:visibility="invisible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </TextView>

    <ImageView
        android:id="@+id/item_upload_delete"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_marginEnd="10dp"
        android:background="@drawable/ic_baseline_close_24"
        app:layout_constraintBottom_toBottomOf="@+id/item_upload_star"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/item_upload_star">

    </ImageView>

    <TextView
        android:id="@+id/item_upload_url"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/item_upload_image"
        app:layout_constraintEnd_toStartOf="@+id/item_upload_star"
        app:layout_constraintStart_toEndOf="@+id/item_upload_rating"
        app:layout_constraintTop_toTopOf="@+id/item_upload_documentid">

    </TextView>

    <ImageView
        android:id="@+id/item_upload_star"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_marginEnd="5dp"
        android:background="@drawable/ic_baseline_star_24"
        app:layout_constraintBottom_toTopOf="@+id/item_upload_image"
        app:layout_constraintEnd_toStartOf="@+id/item_upload_delete"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.551">

    </ImageView>


</androidx.constraintlayout.widget.ConstraintLayout>

 

표시될 아이템은 위의 XML을 따르며 모습은 다음과 같다.

Contents 위에 사진이 올라갈 예정인데 사진의 크기에 따라 맞춰서 올라가기 때문에 여기서는 보이지 않는다.

별점을 표시해주고 별점주기를 누르면 별점을 주는 기능을 추가할 것이며

별을 누를시 찜하기로 넘어가고 X를 클릭시 삭제기능을 넣으려 하였다.

이런 추가 기능들은 다음에 설명하려 한다.

 

이렇게 리사이클러뷰를 만들어주었다면 이제 Fragment에 적용만 해주면 된다.

    private RecyclerView mUploadRecyclerView;
    private UploadAdapter mAdapter;
    private List<Upload> mDatas;
    
    
    
        mUploadRecyclerView = view.findViewById(R.id.home_RecyclerView);
        mDatas = new ArrayList<>();

이렇게 리사이클러뷰와 어댑터, 모델을 연결해준다.

그리고 프래그먼트에서 바로 사진을 업로드하기는 힘들기 때문에 UploadActivity를 새로 만들어주었다.

그리고 이 화면으로 넘어가기 위해 플로팅 버튼을 추가하였다.

        floatingActionButton = view.findViewById(R.id.board_write);
        floatingActionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(getActivity(), UploadActivity.class); //fragment라서 activity intent와는 다른 방식
                // intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                startActivity(intent);
            }
        });

이렇게 하면 플로팅 버튼을 클릭할시 화면인 Intent되어 UploadActivity로 전환될것이다.

 

 

글이 길어져서 이번 글은 여기까지 하고 다음글에서 이어서 작성하도록 해야겠다.

반응형