diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index a551c90..da21469 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -4,24 +4,15 @@
-
+
-
+
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/render.experimental.xml b/.idea/render.experimental.xml
new file mode 100644
index 0000000..8ec256a
--- /dev/null
+++ b/.idea/render.experimental.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 3d8ac8e..f0e0174 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -73,6 +73,8 @@ dependencies {
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-auth")
+ implementation ("com.google.firebase:firebase-firestore:24.7.0")
+ implementation ("com.google.firebase:firebase-storage:20.2.0")// 최신 버전 확인
// Naver Map SDK
implementation("com.naver.maps:map-sdk:3.19.1")
@@ -91,4 +93,7 @@ dependencies {
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation("com.google.firebase:firebase-database")
+ implementation ("com.github.bumptech.glide:glide:4.15.1")
+ annotationProcessor ("com.github.bumptech.glide:compiler:4.15.1")
+
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a24b2af..22af81b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -52,6 +52,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/CheckProfileAndTimeTableFragment/CheckTimeTableFragment.java b/app/src/main/java/com/example/mohassu/CheckProfileAndTimeTableFragment/CheckTimeTableFragment.java
index a9737ee..9555771 100644
--- a/app/src/main/java/com/example/mohassu/CheckProfileAndTimeTableFragment/CheckTimeTableFragment.java
+++ b/app/src/main/java/com/example/mohassu/CheckProfileAndTimeTableFragment/CheckTimeTableFragment.java
@@ -1,49 +1,120 @@
package com.example.mohassu.CheckProfileAndTimeTableFragment;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.example.mohassu.R;
+import com.example.mohassu.models.Friend;
+import com.github.tlaabs.timetableview.TimetableView;
+import com.google.firebase.firestore.FirebaseFirestore;
public class CheckTimeTableFragment extends Fragment {
+ private TimetableView timetableView;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_check_time_table, container, false);
+ return inflater.inflate(R.layout.fragment_check_time_table, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ // 🔥 Back 버튼 클릭 리스너
ImageButton backButton = view.findViewById(R.id.btnBack);
- backButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- // 현재 프래그먼트를 제거하고 백 스택에서 돌아가기
- requireActivity()
- .getSupportFragmentManager()
- .popBackStack();
-
- // `BottomSheetCheckProfileFragment` 다시 표시
- BottomSheetCheckProfileFragment bottomSheet = (BottomSheetCheckProfileFragment)
- requireActivity()
- .getSupportFragmentManager()
- .findFragmentByTag("BottomSheetCheckProfile");
-
- if (bottomSheet != null && bottomSheet.getDialog() != null) {
- bottomSheet.getDialog().show(); // 숨겨진 다이얼로그 다시 표시
- }
- }
- });
+ backButton.setOnClickListener(v -> requireActivity().getSupportFragmentManager().popBackStack());
+
+ // 🔥 TimetableView 초기화
+ timetableView = view.findViewById(R.id.timetable);
+ // 🔥 타이틀 설정
TextView tvTitle = view.findViewById(R.id.tvTitle);
+
+ // 🔥 Bundle에서 친구 정보 가져오기
Bundle args = getArguments();
if (args != null) {
- String userName = args.getString("nickName", "Default User");
- tvTitle.setText(getString(R.string.check_time_table_title, userName));
+ Friend friend = (Friend) args.getSerializable("friend");
+ if (friend != null) {
+ // 🔥 친구 닉네임으로 타이틀 설정
+ tvTitle.setText(getString(R.string.check_time_table_title, friend.getNickname()));
+
+ // 🔥 친구의 시간표 데이터 로드
+ loadFriendTimeTable(friend.getUid());
+ } else {
+ Log.e("CheckTimeTableFragment", "Friend 객체가 null입니다.");
+ }
+ } else {
+ Log.e("CheckTimeTableFragment", "전달된 Bundle이 null입니다.");
+ }
+ }
+
+ private void loadFriendTimeTable(String friendUid) {
+ if (friendUid == null || friendUid.isEmpty()) {
+ Log.e("CheckTimeTableFragment", "friendUid가 null이거나 빈 문자열입니다.");
+ Toast.makeText(requireContext(), "친구의 정보를 불러올 수 없습니다.", Toast.LENGTH_SHORT).show();
+ return;
}
- return view;
+ Log.d("CheckTimeTableFragment", "로드할 친구 UID: " + friendUid);
+
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ db.collection("users").document(friendUid)
+ .get()
+ .addOnSuccessListener(documentSnapshot -> {
+ if (documentSnapshot.exists()) {
+ // 🔥 시간표 데이터 가져오기
+ String timetableData = documentSnapshot.getString("timetableData");
+
+ if (timetableData != null && !timetableData.isEmpty()) {
+ Log.d("CheckTimeTableFragment", "시간표 데이터: " + timetableData);
+
+ // 🔥 TimetableView에 데이터 로드
+ try {
+ timetableView.load(timetableData);
+ Toast.makeText(requireContext(), "시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ Log.e("CheckTimeTableFragment", "시간표 로드 중 오류 발생", e);
+ Toast.makeText(requireContext(), "시간표를 로드할 수 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ Toast.makeText(requireContext(), "시간표 데이터가 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ Log.e("CheckTimeTableFragment", "친구의 프로필을 찾을 수 없습니다.");
+ Toast.makeText(requireContext(), "프로필을 찾을 수 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ })
+ .addOnFailureListener(e -> {
+ Log.e("CheckTimeTableFragment", "시간표 불러오기 실패: " + e.getMessage(), e);
+ Toast.makeText(requireContext(), "시간표 불러오기 실패: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // 🔥 상단 타이틀 숨기기
+ if (requireActivity().getActionBar() != null) {
+ requireActivity().getActionBar().hide();
+ }
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ // 🔥 상단 타이틀 복원
+ if (requireActivity().getActionBar() != null) {
+ requireActivity().getActionBar().show();
+ }
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/CheckProfileBottomSheetFragment.java b/app/src/main/java/com/example/mohassu/CheckProfileBottomSheetFragment.java
new file mode 100644
index 0000000..25b6b53
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/CheckProfileBottomSheetFragment.java
@@ -0,0 +1,86 @@
+package com.example.mohassu;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+
+import com.bumptech.glide.Glide;
+import com.example.mohassu.models.Friend;
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
+
+public class CheckProfileBottomSheetFragment extends BottomSheetDialogFragment {
+
+ // Friend 객체를 전달받는 newInstance 메서드
+ public static CheckProfileBottomSheetFragment newInstance(Friend friend) {
+ CheckProfileBottomSheetFragment fragment = new CheckProfileBottomSheetFragment();
+ Bundle args = new Bundle();
+ args.putSerializable("friend", friend);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_bottom_sheet_check_profile, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ // 🔥 Friend 객체 가져오기
+ Friend friend = (Friend) getArguments().getSerializable("friend");
+
+ if (friend == null) {
+ return;
+ }
+
+ // 📌 UI 요소 초기화
+ TextView nicknameTextView = view.findViewById(R.id.text_nickname);
+ TextView nameTextView = view.findViewById(R.id.text_name);
+ ImageView photoImageView = view.findViewById(R.id.img_profile);
+ Button viewTimeTableButton = view.findViewById(R.id.view_time_table_button);
+ ImageButton btnBottomSheetClose = view.findViewById(R.id.btn_bottomsheet_close);// 🔥 추가된 버튼
+
+ // 🔥 데이터 바인딩
+ nicknameTextView.setText(friend.getNickname() != null ? friend.getNickname() : "닉네임 없음");
+ nameTextView.setText(friend.getName() != null ? friend.getName() : "이름 없음");
+
+ // 🔥 Glide를 활용하여 이미지 로드
+ Glide.with(requireContext())
+ .load(friend.getPhotoUrl())
+ .placeholder(R.drawable.img_logo) // 로딩 중 표시할 이미지
+ .error(R.drawable.img_logo) // 로딩 실패 시 표시할 이미지
+ .into(photoImageView);
+
+
+ // 🔥 "시간표 보기" 버튼 클릭 리스너 추가
+ viewTimeTableButton.setOnClickListener(v -> {
+ Bundle bundle = new Bundle();
+ bundle.putSerializable("friend", friend);
+
+ try {
+ dismiss();
+ NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
+ Log.d("CheckProfileBottomSheetFragment", "NavController 찾기 성공");
+ navController.navigate(R.id.action_checkProfileToCheckTimeTable, bundle);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+
+ btnBottomSheetClose.setOnClickListener(v -> dismiss());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/Constants.java b/app/src/main/java/com/example/mohassu/Constants.java
new file mode 100644
index 0000000..446d7f4
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/Constants.java
@@ -0,0 +1,35 @@
+package com.example.mohassu;
+
+import com.naver.maps.geometry.LatLng;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Constants {
+ public static final List PLACES = new ArrayList<>();
+
+ static {
+ PLACES.add(new PlaceInfo("정보과학관", new LatLng(37.494576, 126.959706), 30));
+ PLACES.add(new PlaceInfo("한경직기념관", new LatLng(37.495619, 126.957444), 30));
+ PLACES.add(new PlaceInfo("중앙도서관", new LatLng(37.496325, 126.958585), 30));
+ PLACES.add(new PlaceInfo("전산관", new LatLng(37.495451, 126.959518), 30));
+ PLACES.add(new PlaceInfo("형남공학관", new LatLng(37.495732, 126.956152), 30));
+ PLACES.add(new PlaceInfo("안익태기념관", new LatLng(37.495753, 126.955012), 30));
+ PLACES.add(new PlaceInfo("경상관", new LatLng(37.496549, 126.955030), 30));
+ PLACES.add(new PlaceInfo("문화관", new LatLng(37.496576, 126.954271), 30));
+ PLACES.add(new PlaceInfo("베어드홀", new LatLng(37.496506, 126.956273), 30));
+ PLACES.add(new PlaceInfo("학생회관", new LatLng(37.496873, 126.956308), 30));
+ PLACES.add(new PlaceInfo("숭덕경상관", new LatLng(37.496942, 126.954923), 30));
+ PLACES.add(new PlaceInfo("백마관", new LatLng(37.497830, 126.956273), 30));
+ PLACES.add(new PlaceInfo("벤처관", new LatLng(37.497544, 126.957438), 30));
+ PLACES.add(new PlaceInfo("진리관", new LatLng(37.496906, 126.957495), 30));
+ PLACES.add(new PlaceInfo("조만식기념관", new LatLng(37.497249, 126.958212), 30));
+ PLACES.add(new PlaceInfo("미래관", new LatLng( 37.495610, 126.958487), 30));
+
+
+
+
+
+ // 필요시 추가
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/DialogFragment/AddFriendDialogFragment.java b/app/src/main/java/com/example/mohassu/DialogFragment/AddFriendDialogFragment.java
new file mode 100644
index 0000000..7367d7b
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/DialogFragment/AddFriendDialogFragment.java
@@ -0,0 +1,117 @@
+package com.example.mohassu.DialogFragment;
+
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+
+import com.example.mohassu.R;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.GeoPoint;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AddFriendDialogFragment extends DialogFragment {
+
+ private EditText emailInput;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.dialog_add_friend, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ emailInput = view.findViewById(R.id.emailInput); // 이메일 입력 필드
+
+ // "친구 추가" 버튼 클릭 리스너
+ view.findViewById(R.id.btnAddFriend).setOnClickListener(v -> addFriend());
+
+ // "취소" 버튼 클릭 리스너
+ view.findViewById(R.id.btnCancelFriend).setOnClickListener(v -> dismiss());
+ }
+
+ private void addFriend() {
+ String email = emailInput.getText().toString().trim();
+
+ if (TextUtils.isEmpty(email)) {
+ Toast.makeText(requireContext(), "이메일을 입력해주세요.", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ FirebaseAuth auth = FirebaseAuth.getInstance();
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+
+ String currentUserId = auth.getCurrentUser().getUid(); // 현재 로그인한 사용자 UID
+
+ // 이메일로 사용자 검색
+ //추가한 코드: 다른 데이터(좌표, 이름 등)
+ db.collection("users")
+ .whereEqualTo("email", email)
+ .get()
+ .addOnCompleteListener(task -> {
+ if (task.isSuccessful() && !task.getResult().isEmpty()) {
+ // 검색된 사용자 정보
+ String friendUserId = task.getResult().getDocuments().get(0).getId();
+ String name = task.getResult().getDocuments().get(0).getString("name");
+ String nickname = task.getResult().getDocuments().get(0).getString("nickname");
+ String photoUrl = task.getResult().getDocuments().get(0).getString("photoUrl");
+ String place = task.getResult().getDocuments().get(0).getString("place");
+ String statusMessage = task.getResult().getDocuments().get(0).getString("statusMessage");
+
+ db.collection("users").document(friendUserId)
+ .collection("location")
+ .document("currentLocation")
+ .get()
+ .addOnSuccessListener(locationDoc -> {
+ if (locationDoc.exists()) {
+ GeoPoint location = locationDoc.getGeoPoint("location");
+
+ if (location == null) {
+ location = new GeoPoint(0, 0); // 기본 위치 설정 (위도, 경도)
+ } // 위치 null 튕김 방지
+
+
+ // 친구 추가 로직
+ Map friendData = new HashMap<>();
+ friendData.put("friendUserId", friendUserId);
+ friendData.put("email", email);
+ friendData.put("name", name);
+ friendData.put("nickname", nickname);
+ friendData.put("photoUrl", photoUrl);
+ friendData.put("place", place);
+ friendData.put("location", location);
+ if (statusMessage != null)
+ friendData.put("statusMessage", statusMessage);
+
+
+ db.collection("users").document(currentUserId)
+ .collection("friends").document(friendUserId)
+ .set(friendData)
+ .addOnSuccessListener(aVoid -> {
+ Toast.makeText(requireContext(), "친구 추가 완료!", Toast.LENGTH_SHORT).show();
+ dismiss(); // 다이얼로그 닫기
+ })
+ .addOnFailureListener(e -> {
+ Toast.makeText(requireContext(), "친구 추가 실패: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ });
+ } else {
+ Toast.makeText(requireContext(), "사용자를 찾을 수 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/DialogFragment/ClassAddDialogFragment.java b/app/src/main/java/com/example/mohassu/DialogFragment/ClassAddDialogFragment.java
index 70a2a46..fd9acd1 100644
--- a/app/src/main/java/com/example/mohassu/DialogFragment/ClassAddDialogFragment.java
+++ b/app/src/main/java/com/example/mohassu/DialogFragment/ClassAddDialogFragment.java
@@ -19,14 +19,15 @@
public class ClassAddDialogFragment extends DialogFragment {
- private TextView selectedLocationButton = null;
+ private TextView selectedLocationButton = null; // 강의 장소 선택 로직을 위해서 정의
+ private String selectedClassPlace = ""; // 선택된 강의 장소를 저장하는 변수
+
public interface OnClassAddedListener {
void onClassAdded(String className, String classPlace, int day, int startHour, int startMinute, int endHour, int endMinute);
}
private OnClassAddedListener listener;
- private String selectedClassPlace = ""; // 선택된 강의 장소를 저장하는 변수
public void setOnClassAddedListener(OnClassAddedListener listener) {
this.listener = listener;
diff --git a/app/src/main/java/com/example/mohassu/DialogFragment/ClassEditDialogFragment.java b/app/src/main/java/com/example/mohassu/DialogFragment/ClassEditDialogFragment.java
deleted file mode 100644
index 86c5c7d..0000000
--- a/app/src/main/java/com/example/mohassu/DialogFragment/ClassEditDialogFragment.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.example.mohassu.DialogFragment;
-
-public class ClassEditDialogFragment {
-}
diff --git a/app/src/main/java/com/example/mohassu/DialogFragment/ClassEditOrDeleteDialogFragment.java b/app/src/main/java/com/example/mohassu/DialogFragment/ClassEditOrDeleteDialogFragment.java
new file mode 100644
index 0000000..e35d8c5
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/DialogFragment/ClassEditOrDeleteDialogFragment.java
@@ -0,0 +1,193 @@
+package com.example.mohassu.DialogFragment;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.TimePicker;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+
+import com.example.mohassu.R;
+import com.github.tlaabs.timetableview.Schedule;
+import com.github.tlaabs.timetableview.Time;
+
+public class ClassEditOrDeleteDialogFragment extends DialogFragment {
+
+ private TextView selectedLocationButton = null; // 강의 장소 선택 로직을 위해서 정의
+ private String selectedClassPlace = ""; // 선택된 강의 장소를 저장하는 변수
+
+ public interface OnClassEditOrDeleteListener {
+ void onEdit(Schedule editedSchedule);
+ void onDelete();
+ }
+
+ private OnClassEditOrDeleteListener listener;
+
+ public void setOnClassEditOrDeleteListener(OnClassEditOrDeleteListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public int getTheme() {
+ return R.style.CustomDialogStyle;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ if (getDialog() != null && getDialog().getWindow() != null) {
+ getDialog().getWindow().setLayout(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ );
+ }
+ }
+
+ public static ClassEditOrDeleteDialogFragment newInstance(Schedule existingSchedule) {
+ ClassEditOrDeleteDialogFragment fragment = new ClassEditOrDeleteDialogFragment();
+ Bundle args = new Bundle();
+ args.putSerializable("schedule", existingSchedule);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.dialog_class_edit_or_delete, container, false);
+
+ EditText classTitle = view.findViewById(R.id.input_class_name);
+ Spinner spinnerDay = view.findViewById(R.id.spinner_day);
+ Spinner spinnerStartTime = view.findViewById(R.id.start_time);
+ Spinner spinnerEndTime = view.findViewById(R.id.end_time);
+ EditText inputClassPlace = view.findViewById(R.id.input_class_place);
+ Button editSaveButton = view.findViewById(R.id.btn_edit_save);
+ Button deleteButton = view.findViewById(R.id.btn_delete);
+ ImageButton closeButton = view.findViewById(R.id.btn_close);
+ LinearLayout horizontalContainer = view.findViewById(R.id.horizontal_spinner_container);
+
+ Schedule existingSchedule = new Schedule();
+ existingSchedule = (Schedule) getArguments().getSerializable("schedule");
+
+ // 닫기 버튼 동작
+ closeButton.setOnClickListener(v -> dismiss());
+
+ // strings.xml에서 강의 장소 배열 가져오기
+ String[] locations = getResources().getStringArray(R.array.locations);
+
+ // 동적으로 버튼 추가
+ for (String location : locations) {
+ TextView locationButton = new TextView(requireContext());
+ locationButton.setText(location);
+ locationButton.setBackgroundResource(R.drawable.background_banner_white); // 기본 배경
+ locationButton.setPadding(16, 8, 16, 8);
+ locationButton.setTextColor(getResources().getColor(android.R.color.black));
+ locationButton.setGravity(View.TEXT_ALIGNMENT_CENTER);
+
+ // 레이아웃 매개변수 설정
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ );
+ params.setMargins(8, 0, 8, 0); // 버튼 간격
+ locationButton.setLayoutParams(params);
+
+ // 버튼 클릭 이벤트
+ locationButton.setOnClickListener(v -> {
+ // 이전에 선택된 버튼이 있는 경우, 상태 해제
+ if (selectedLocationButton != null && selectedLocationButton != locationButton) {
+ selectedLocationButton.setBackgroundResource(R.drawable.background_banner_white); // 기본 배경
+ selectedLocationButton.setTextColor(getResources().getColor(android.R.color.black)); // 기본 텍스트 색상
+ }
+
+ // 현재 버튼을 선택 상태로 설정
+ selectedLocationButton = locationButton;
+ selectedLocationButton.setBackgroundResource(R.drawable.background_banner_selected); // 선택된 배경
+ selectedLocationButton.setTextColor(getResources().getColor(android.R.color.white)); // 선택된 텍스트 색상
+
+ // 선택된 장소를 저장
+ selectedClassPlace = location;
+ inputClassPlace.setText(location); // EditText에 설정
+ });
+
+ // 이전에 저장된 장소 선택
+ if (existingSchedule != null && location.equals(existingSchedule.getClassPlace())) {
+ selectedLocationButton = locationButton;
+ selectedLocationButton.setBackgroundResource(R.drawable.background_banner_selected);
+ selectedLocationButton.setTextColor(getResources().getColor(android.R.color.white));
+ }
+
+ horizontalContainer.addView(locationButton);
+ }
+
+ // 기존 데이터 설정
+ if (existingSchedule != null) {
+ classTitle.setText(existingSchedule.getClassTitle());
+ inputClassPlace.setText(existingSchedule.getClassPlace());
+
+ // Day 스피너 설정 (0: Monday, 1: Tuesday, ...)
+ spinnerDay.setSelection(existingSchedule.getDay());
+
+ // Start Time 설정
+ String startTime = String.format("%02d:%02d", existingSchedule.getStartTime().getHour(), existingSchedule.getStartTime().getMinute());
+ setSpinnerSelection(spinnerStartTime, startTime);
+
+ // End Time 설정
+ String endTime = String.format("%02d:%02d", existingSchedule.getEndTime().getHour(), existingSchedule.getEndTime().getMinute());
+ setSpinnerSelection(spinnerEndTime, endTime);
+ }
+
+ // 수정 버튼 동작
+ editSaveButton.setOnClickListener(v -> {
+ if (listener != null) {
+ String classTitleText = classTitle.getText().toString();
+ String classPlaceText = inputClassPlace.getText().toString();
+ int day = spinnerDay.getSelectedItemPosition();
+ int startHour = Integer.parseInt(spinnerStartTime.getSelectedItem().toString().split(":")[0]);
+ int startMinute = Integer.parseInt(spinnerStartTime.getSelectedItem().toString().split(":")[1]);
+ int endHour = Integer.parseInt(spinnerEndTime.getSelectedItem().toString().split(":")[0]);
+ int endMinute = Integer.parseInt(spinnerEndTime.getSelectedItem().toString().split(":")[1]);
+
+ // 수정된 Schedule 객체 생성
+ Schedule editedSchedule = new Schedule();
+ editedSchedule.setClassTitle(classTitleText);
+ editedSchedule.setClassPlace(classPlaceText);
+ editedSchedule.setDay(day);
+ editedSchedule.setStartTime(new Time(startHour, startMinute));
+ editedSchedule.setEndTime(new Time(endHour, endMinute));
+
+ // 수정된 데이터를 listener를 통해 전달
+ listener.onEdit(editedSchedule);
+ }
+ dismiss();
+ });
+
+ // 삭제 버튼 동작
+ deleteButton.setOnClickListener(v -> {
+ if (listener != null) {
+ listener.onDelete();
+ }
+ dismiss();
+ });
+
+ return view;
+ }
+
+ private void setSpinnerSelection(Spinner spinner, String value) {
+ for (int i = 0; i < spinner.getCount(); i++) {
+ if (spinner.getItemAtPosition(i).toString().equals(value)) {
+ spinner.setSelection(i);
+ break;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup1IDAndPWFragment.java b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup1IDAndPWFragment.java
index 50f4e54..118ee2b 100644
--- a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup1IDAndPWFragment.java
+++ b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup1IDAndPWFragment.java
@@ -2,6 +2,8 @@
import android.os.Bundle;
import android.text.TextUtils;
+import android.util.Log;
+import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -16,21 +18,20 @@
import androidx.navigation.Navigation;
import com.example.mohassu.R;
+import com.google.firebase.auth.ActionCodeSettings;
import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.database.DataSnapshot;
-import com.google.firebase.database.DatabaseReference;
-import com.google.firebase.database.FirebaseDatabase;
+import com.google.firebase.auth.FirebaseUser;
public class Signup1IDAndPWFragment extends Fragment {
private FirebaseAuth auth; // Firebase Auth 인스턴스
- private DatabaseReference databaseReference; // Firebase Database Reference
- private EditText etId, etPassword, etConfirmPassword;
- private TextView tvIdError, tvPasswordError;
- private Button btnCheckId, btnSignupNext;
+ private EditText etEmail, etPassword, etConfirmPassword;
+ private TextView tvEmailError, tvPasswordError;
+ private Button btnCheckEmail, btnSignupNext,btnVerifyEmail;
- private boolean isIdChecked = false; // 아이디 중복 검사 여부
+ private boolean isEmailChecked = false; // 이메일 중복 검사 여부
+ private ActionCodeSettings actionCodeSettings;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -51,68 +52,90 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
// Firebase 초기화
auth = FirebaseAuth.getInstance();
- databaseReference = FirebaseDatabase.getInstance().getReference("users"); // Firebase Database 경로
// UI 요소 초기화
- etId = view.findViewById(R.id.etId);
+ etEmail = view.findViewById(R.id.etEmail); // 이메일 입력 필드
etPassword = view.findViewById(R.id.etPassword);
etConfirmPassword = view.findViewById(R.id.etConfirmPassword);
- tvIdError = view.findViewById(R.id.tvIdError);
+ tvEmailError = view.findViewById(R.id.tvEmaildError);
tvPasswordError = view.findViewById(R.id.tvPasswordError);
- btnCheckId = view.findViewById(R.id.btnCheckId);
+
+
+ btnCheckEmail = view.findViewById(R.id.btnCheckEmail);
+ btnVerifyEmail = view.findViewById(R.id.btnSendVerification);
btnSignupNext = view.findViewById(R.id.btnNext);
- // 아이디 중복 검사
- btnCheckId.setOnClickListener(v -> checkIdDuplication());
+ // 이메일 중복 및 유효성 검사 버튼 클릭 리스너
+ btnCheckEmail.setOnClickListener(v -> checkEmailDuplication());
- // 회원가입 버튼 클릭
- btnSignupNext.setOnClickListener(v -> registerUser());
+ // 회원가입 버튼 클릭 리스너
+ btnVerifyEmail.setOnClickListener(v -> registerUser());
}
- private void checkIdDuplication() {
- String userId = etId.getText().toString().trim();
+ private void checkEmailDuplication() {
+ String email = etEmail.getText().toString().trim();
+ String dummyPassword = "DummyPassword123"; // 테스트용 비밀번호 (중복 검사에만 사용)
- if (TextUtils.isEmpty(userId)) {
- tvIdError.setText("아이디를 입력해주세요.");
- tvIdError.setVisibility(View.VISIBLE);
+ // 이메일 형식 유효성 검사
+ if (!isValidEmail(email)) {
+ tvEmailError.setText("유효한 이메일 주소를 입력해주세요.");
+ tvEmailError.setVisibility(View.VISIBLE);
return;
}
- databaseReference.child(userId).get().addOnCompleteListener(task -> {
- if (task.isSuccessful()) {
- DataSnapshot dataSnapshot = task.getResult();
- if (dataSnapshot.exists()) {
- tvIdError.setText("이미 사용 중인 아이디입니다.");
- tvIdError.setVisibility(View.VISIBLE);
- isIdChecked = false;
- } else {
- tvIdError.setVisibility(View.GONE);
- Toast.makeText(requireContext(), "사용 가능한 아이디입니다.", Toast.LENGTH_SHORT).show();
- isIdChecked = true;
- }
- } else {
- Toast.makeText(requireContext(), "아이디 중복 검사 실패: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
- }
- });
+ // Firebase Authentication에서 중복 이메일 검사
+ auth.createUserWithEmailAndPassword(email, dummyPassword)
+ .addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ // 중복되지 않은 이메일 -> 테스트 계정 삭제
+ auth.getCurrentUser().delete()
+ .addOnCompleteListener(deleteTask -> {
+ if (deleteTask.isSuccessful()) {
+ tvEmailError.setVisibility(View.GONE);
+ Toast.makeText(requireContext(), "사용 가능한 이메일입니다.", Toast.LENGTH_SHORT).show();
+ isEmailChecked = true;
+ }
+ });
+ } else {
+ // 중복된 이메일
+ if (task.getException() != null && task.getException().getMessage().contains("email address is already in use")) {
+ tvEmailError.setText("이미 사용 중인 이메일입니다.");
+ tvEmailError.setVisibility(View.VISIBLE);
+ isEmailChecked = false;
+ } else {
+ Toast.makeText(requireContext(), "중복 검사 실패: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
}
+
private void registerUser() {
- String userId = etId.getText().toString().trim();
+ String email = etEmail.getText().toString().trim();
String password = etPassword.getText().toString().trim();
String confirmPassword = etConfirmPassword.getText().toString().trim();
- // 유효성 검사
- if (!isIdChecked) {
- Toast.makeText(requireContext(), "아이디 중복 검사를 진행해주세요.", Toast.LENGTH_SHORT).show();
+ // 이메일 형식 검사
+ if (!isValidEmail(email)) {
+ tvEmailError.setText("유효한 이메일 주소를 입력해주세요.");
+ tvEmailError.setVisibility(View.VISIBLE);
return;
}
+ // 이메일 중복 검사 여부 확인
+ if (!isEmailChecked) {
+ Toast.makeText(requireContext(), "이메일 중복 검사를 진행해주세요.", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // 비밀번호 입력 여부 확인
if (TextUtils.isEmpty(password) || TextUtils.isEmpty(confirmPassword)) {
tvPasswordError.setText("비밀번호를 입력해주세요.");
tvPasswordError.setVisibility(View.VISIBLE);
return;
}
+ // 비밀번호 일치 확인
if (!password.equals(confirmPassword)) {
tvPasswordError.setText("비밀번호가 일치하지 않습니다.");
tvPasswordError.setVisibility(View.VISIBLE);
@@ -122,28 +145,41 @@ private void registerUser() {
tvPasswordError.setVisibility(View.GONE);
// Firebase Authentication 회원가입
- auth.createUserWithEmailAndPassword(userId + "@gmail.com", password)
+ auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(requireActivity(), task -> {
if (task.isSuccessful()) {
- // 이메일 인증 메일 전송
+ // 인증 이메일 발송
auth.getCurrentUser().sendEmailVerification()
.addOnCompleteListener(emailTask -> {
if (emailTask.isSuccessful()) {
- Toast.makeText(requireContext(), "회원가입 성공! 이메일 인증을 완료해주세요.", Toast.LENGTH_SHORT).show();
-
- // Firebase Realtime Database에 사용자 데이터 저장
- databaseReference.child(userId).setValue(userId)
- .addOnCompleteListener(dbTask -> {
- if (dbTask.isSuccessful()) {
- // 이메일 인증 안내 화면 또는 다음 Fragment로 이동
- NavController navController = Navigation.findNavController(requireView());
- navController.navigate(R.id.actionNextToSignup2); // 적절한 Action ID로 변경
- } else {
- Toast.makeText(requireContext(), "데이터 저장 실패: " + dbTask.getException().getMessage(), Toast.LENGTH_SHORT).show();
- }
- });
+ Toast.makeText(requireContext(), "회원가입 성공! 인증 이메일을 확인해주세요.", Toast.LENGTH_SHORT).show();
+
+// // 인증 확인 버튼 활성화
+// Button btnVerifyEmail = requireView().findViewById(R.id.btnVerifyEmail);
+
+ // 이메일 인증 확인 버튼 클릭 리스너 설정
+ btnSignupNext.setOnClickListener(v -> {
+ FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
+ if (user != null) {
+ user.reload() // 사용자 정보 새로고침
+ .addOnCompleteListener(reloadTask -> {
+ NavController navController = Navigation.findNavController(requireView());
+ navController.navigate(R.id.actionNextToSignup2); // 적절한 Action ID로 변경
+// if (user.isEmailVerified()) {
+// Toast.makeText(requireContext(), "이메일 인증 완료!", Toast.LENGTH_SHORT).show();
+// // 다음 Fragment로 이동
+// NavController navController = Navigation.findNavController(requireView());
+// navController.navigate(R.id.actionNextToSignup2); // 적절한 Action ID로 변경
+// } else {
+// Toast.makeText(requireContext(), "이메일 인증을 완료해주세요!", Toast.LENGTH_SHORT).show();
+// }
+ });
+ } else {
+ Toast.makeText(requireContext(), "사용자 정보를 확인할 수 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
} else {
- Toast.makeText(requireContext(), "인증 이메일 전송 실패: " + emailTask.getException().getMessage(), Toast.LENGTH_SHORT).show();
+ Toast.makeText(requireContext(), "인증 이메일 발송 실패: " + emailTask.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
});
} else {
@@ -151,4 +187,9 @@ private void registerUser() {
}
});
}
+
+ // 유효한 이메일 형식인지 확인
+ private boolean isValidEmail(String email) {
+ return !TextUtils.isEmpty(email) && Patterns.EMAIL_ADDRESS.matcher(email).matches();
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup2DetailFragment.java b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup2DetailFragment.java
index b19a074..5282afe 100644
--- a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup2DetailFragment.java
+++ b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup2DetailFragment.java
@@ -1,6 +1,131 @@
+//package com.example.mohassu.LoginAndSignUpFragment;
+//
+//import android.os.Bundle;
+//import android.view.LayoutInflater;
+//import android.view.View;
+//import android.view.ViewGroup;
+//import android.widget.Button;
+//import android.widget.DatePicker;
+//import android.widget.EditText;
+//import android.widget.Toast;
+//
+//import androidx.annotation.NonNull;
+//import androidx.fragment.app.Fragment;
+//import androidx.navigation.NavController;
+//import androidx.navigation.Navigation;
+//
+//import com.example.mohassu.R;
+//import com.google.firebase.auth.FirebaseAuth;
+//import com.google.firebase.database.DatabaseReference;
+//import com.google.firebase.database.FirebaseDatabase;
+//
+//public class Signup2DetailFragment extends Fragment {
+//
+// private EditText etNickname, etName;
+// private DatePicker dpBirthdate;
+// private Button signupNextButton;
+//
+// private FirebaseAuth mAuth;
+// private DatabaseReference databaseReference;
+//
+//// @Override
+//// protected void onCreate(Bundle savedInstanceState) {
+//// super.onCreate(savedInstanceState);
+//// Setcon
+////
+//// //androidx.fragment.app.FragmentManager
+//// //androidx.fragment.app.FragmentTransaction
+////
+//// }
+//
+// @Override
+// public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+//
+// return inflater.inflate(R.layout.fragment_sign_up2, container, false);
+// }
+//
+// @Override
+// public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
+// super.onViewCreated(view, savedInstanceState);
+//
+//// getParentFragmentManager()
+//// .beginTransaction()
+//// .replace(R.id.main,new Signup3ProfileFragment())
+//// .commit();
+//
+// // NavController 초기화
+// NavController navController = Navigation.findNavController(view);
+//
+// // 뒤로가기 버튼에 클릭 리스너 추가
+// view.findViewById(R.id.btnBack).setOnClickListener(v -> {
+// navController.navigateUp();
+// });
+//
+// // Firebase 초기화
+// mAuth = FirebaseAuth.getInstance();
+// databaseReference = FirebaseDatabase.getInstance().getReference("users");
+//
+// // UI 초기화
+// etNickname = view.findViewById(R.id.etNickname);
+// etName = view.findViewById(R.id.etName);
+// dpBirthdate = view.findViewById(R.id.dpSpinner);
+// signupNextButton = view.findViewById(R.id.btnNext);
+//
+// signupNextButton.setOnClickListener(v -> saveUserProfile(view));
+// }
+//
+// private void saveUserProfile(View view) {
+// String nickname = etNickname.getText().toString().trim();
+// String name = etName.getText().toString().trim();
+// int day = dpBirthdate.getDayOfMonth();
+// int month = dpBirthdate.getMonth() + 1; // Month is 0-based in DatePicker
+// int year = dpBirthdate.getYear();
+// String birthdate = year + "-" + month + "-" + day;
+//
+// // 필드 유효성 검사
+// if (nickname.isEmpty() || name.isEmpty()) {
+// Toast.makeText(requireContext(), "모든 필드를 입력해주세요.", Toast.LENGTH_SHORT).show();
+// return;
+// }
+//
+// // Firebase Realtime Database에 저장
+// String uid = mAuth.getCurrentUser().getUid();
+// UserProfile userProfile = new UserProfile(nickname, name, birthdate);
+//
+// databaseReference.child(uid).setValue(userProfile)
+// .addOnCompleteListener(task -> {
+// if (task.isSuccessful()) {
+// Toast.makeText(requireContext(), "프로필 저장 성공!", Toast.LENGTH_SHORT).show();
+//
+// // 다음 Fragment로 이동
+// NavController navController = Navigation.findNavController(requireView());
+// navController.navigate(R.id.actionNextToSignup3); // 적절한 Action ID로 변경
+// } else {
+// Toast.makeText(requireContext(), "프로필 저장 실패: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
+// }
+// });
+// }
+//
+// public static class UserProfile {
+// public String nickname;
+// public String name;
+// public String birthdate;
+//
+// public UserProfile() {
+// // 기본 생성자
+// }
+//
+// public UserProfile(String nickname, String name, String birthdate) {
+// this.nickname = nickname;
+// this.name = name;
+// this.birthdate = birthdate;
+// }
+// }
+//}
package com.example.mohassu.LoginAndSignUpFragment;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -16,17 +141,21 @@
import com.example.mohassu.R;
import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.database.DatabaseReference;
-import com.google.firebase.database.FirebaseDatabase;
+import com.google.firebase.firestore.FirebaseFirestore;
+
+import java.util.HashMap;
+import java.util.Map;
public class Signup2DetailFragment extends Fragment {
+ private static final String TAG = "Signup2DetailFragment";
+
private EditText etNickname, etName;
private DatePicker dpBirthdate;
private Button signupNextButton;
private FirebaseAuth mAuth;
- private DatabaseReference databaseReference;
+ private FirebaseFirestore db;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -37,17 +166,9 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- // NavController 초기화
- NavController navController = Navigation.findNavController(view);
-
- // 뒤로가기 버튼에 클릭 리스너 추가
- view.findViewById(R.id.btnBack).setOnClickListener(v -> {
- navController.navigateUp();
- });
-
// Firebase 초기화
mAuth = FirebaseAuth.getInstance();
- databaseReference = FirebaseDatabase.getInstance().getReference("users");
+ db = FirebaseFirestore.getInstance();
// UI 초기화
etNickname = view.findViewById(R.id.etNickname);
@@ -55,6 +176,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
dpBirthdate = view.findViewById(R.id.dpSpinner);
signupNextButton = view.findViewById(R.id.btnNext);
+ // 다음 버튼 클릭 리스너
signupNextButton.setOnClickListener(v -> saveUserProfile(view));
}
@@ -72,37 +194,29 @@ private void saveUserProfile(View view) {
return;
}
- // Firebase Realtime Database에 저장
+ // 현재 사용자 UID 가져오기
String uid = mAuth.getCurrentUser().getUid();
- UserProfile userProfile = new UserProfile(nickname, name, birthdate);
-
- databaseReference.child(uid).setValue(userProfile)
- .addOnCompleteListener(task -> {
- if (task.isSuccessful()) {
- Toast.makeText(requireContext(), "프로필 저장 성공!", Toast.LENGTH_SHORT).show();
-
- // 다음 Fragment로 이동
- NavController navController = Navigation.findNavController(requireView());
- navController.navigate(R.id.actionNextToSignup3); // 적절한 Action ID로 변경
- } else {
- Toast.makeText(requireContext(), "프로필 저장 실패: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
- }
+ String email = mAuth.getCurrentUser().getEmail();
+
+ // Firestore에 사용자 정보 저장
+ Map userProfile = new HashMap<>();
+ userProfile.put("email",email);
+ userProfile.put("nickname", nickname);
+ userProfile.put("name", name);
+ userProfile.put("birthDate", birthdate);
+
+ db.collection("users").document(uid)
+ .set(userProfile)
+ .addOnSuccessListener(aVoid -> {
+ Toast.makeText(requireContext(), "프로필 저장 성공!", Toast.LENGTH_SHORT).show();
+
+ // 다음 프래그먼트로 이동
+ NavController navController = Navigation.findNavController(view);
+ navController.navigate(R.id.actionNextToSignup3); // 적절한 Action ID로 변경
+ })
+ .addOnFailureListener(e -> {
+ Toast.makeText(requireContext(), "Firestore 저장 실패: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Firestore Error", e);
});
}
-
- public static class UserProfile {
- public String nickname;
- public String name;
- public String birthdate;
-
- public UserProfile() {
- // 기본 생성자
- }
-
- public UserProfile(String nickname, String name, String birthdate) {
- this.nickname = nickname;
- this.name = name;
- this.birthdate = birthdate;
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup3ProfileFragment.java b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup3ProfileFragment.java
index 79c0ce4..50e3258 100644
--- a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup3ProfileFragment.java
+++ b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup3ProfileFragment.java
@@ -20,8 +20,15 @@
import androidx.navigation.Navigation;
import com.example.mohassu.R;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.storage.FirebaseStorage;
+import com.google.firebase.storage.StorageReference;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
public class Signup3ProfileFragment extends Fragment {
@@ -32,6 +39,9 @@ public class Signup3ProfileFragment extends Fragment {
private Button signupNextButton, skipButton;
private Uri selectedImageUri; // 선택된 이미지의 URI 저장
+ private FirebaseStorage storage;
+ private FirebaseFirestore db;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_sign_up3, container, false);
@@ -41,6 +51,10 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ // Firebase 초기화
+ storage = FirebaseStorage.getInstance();
+ db = FirebaseFirestore.getInstance();
+
// NavController 초기화
NavController navController = Navigation.findNavController(view);
@@ -61,13 +75,11 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
// 다음 버튼 클릭 리스너
signupNextButton.setOnClickListener(v -> {
if (selectedImageUri != null) {
- // 선택된 이미지 URI를 저장하거나 업로드 로직 추가
- Toast.makeText(requireContext(), "프로필이 저장되었습니다!", Toast.LENGTH_SHORT).show();
+ // 프로필 사진 업로드
+ uploadProfileImage(navController);
} else {
Toast.makeText(requireContext(), "프로필을 선택하지 않았습니다.", Toast.LENGTH_SHORT).show();
}
- // 다음 Fragment로 이동
- navController.navigate(R.id.actionNextToSignup4);
});
// 건너뛰기 버튼 클릭 리스너
@@ -100,4 +112,33 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
}
}
}
+
+ // Firebase Storage에 프로필 사진 업로드
+ private void uploadProfileImage(NavController navController) {
+ if (selectedImageUri != null) {
+ String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
+ StorageReference storageRef = storage.getReference().child("profilePictures/" + UUID.randomUUID().toString());
+
+ storageRef.putFile(selectedImageUri)
+ .addOnSuccessListener(taskSnapshot -> storageRef.getDownloadUrl().addOnSuccessListener(uri -> {
+ // Firestore에 사진 URL 저장
+ Map updates = new HashMap<>();
+ updates.put("photoUrl", uri.toString());
+
+ db.collection("users").document(userId)
+ .update(updates)
+ .addOnSuccessListener(aVoid -> {
+ Toast.makeText(requireContext(), "프로필 사진 저장 성공!", Toast.LENGTH_SHORT).show();
+ // 다음 Fragment로 이동
+ navController.navigate(R.id.actionNextToSignup4);
+ })
+ .addOnFailureListener(e -> {
+ Toast.makeText(requireContext(), "Firestore 저장 실패: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ });
+ }))
+ .addOnFailureListener(e -> {
+ Toast.makeText(requireContext(), "사진 업로드 실패: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ });
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup4TimeTableFragment.java b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup4TimeTableFragment.java
index 8906c1f..77b31ca 100644
--- a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup4TimeTableFragment.java
+++ b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/Signup4TimeTableFragment.java
@@ -1,29 +1,55 @@
package com.example.mohassu.LoginAndSignUpFragment;
+import android.content.Context;
+import android.content.SharedPreferences;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import com.example.mohassu.DialogFragment.ClassAddDialogFragment;
-import com.example.mohassu.DialogFragment.ClassEditDialogFragment;
+import com.example.mohassu.DialogFragment.ClassEditOrDeleteDialogFragment;
import com.example.mohassu.R;
+import com.github.tlaabs.timetableview.Schedule;
+import com.github.tlaabs.timetableview.Time;
+import com.github.tlaabs.timetableview.TimetableView;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.FirebaseFirestore;
+
+import java.util.ArrayList;
+import java.util.HashMap;
public class Signup4TimeTableFragment extends Fragment {
+
+ private static final String PREFS_NAME = "TimetablePrefs"; //회원가입1에서 받은 이메일을 넣어주면 될 듯 -> 지금은 그냥 휴대폰의 아무유저나 다 동일하게 되어있음..
+ private static final String TIMETABLE_KEY = "timetable";
+
+ private TimetableView timetable;
+ private FirebaseFirestore db;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_sign_up4, container, false);
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ db = FirebaseFirestore.getInstance();
+ timetable = view.findViewById(R.id.timetable);
+
+ // Firestore에서 시간표 불러오기
+ loadTimetableFromFirestoreStructured();
+
// NavController 초기화
NavController navController = Navigation.findNavController(view);
@@ -35,20 +61,199 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
// 수업 추가하기 dialog
view.findViewById(R.id.btnAddClass).setOnClickListener(v -> {
ClassAddDialogFragment classAddDialogFragment = new ClassAddDialogFragment();
+ classAddDialogFragment.setOnClassAddedListener((className, classPlace, day, startHour, startMinute, endHour, endMinute) -> {
+ // Validate inputs
+ if (className.isEmpty() || classPlace.isEmpty() || startHour > endHour || (startHour == endHour && startMinute >= endMinute)) {
+ if (className.isEmpty() || classPlace.isEmpty()) {
+ Toast.makeText(requireContext(), "전부 입력해주세요!", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(requireContext(), "시작 시간이 종료 시간보다 빠르거나 같아야 합니다.", Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ addScheduleToTimetable(className, classPlace, day, startHour, startMinute, endHour, endMinute);
+ }
+ });
classAddDialogFragment.show(requireActivity().getSupportFragmentManager(), "ClassAddDialog");
});
- // 다음 프레그먼트를 클릭 시 다음 Fragment로 이동
+ timetable.setOnStickerSelectEventListener((idx, schedules) -> {
+ // 다이얼로그 프래그먼트 호출
+ ClassEditOrDeleteDialogFragment classEditOrDeleteDialogFragment = ClassEditOrDeleteDialogFragment.newInstance(schedules.get(0));
+ Log.d("StickerSelectEvent", "schedule idx : " + idx);
+ classEditOrDeleteDialogFragment.setOnClassEditOrDeleteListener(new ClassEditOrDeleteDialogFragment.OnClassEditOrDeleteListener() {
+ @Override
+ public void onEdit(Schedule editedSchedule) {
+ // 기존 스티커 수정
+ ArrayList updatedSchedules = new ArrayList<>();
+ updatedSchedules.add(editedSchedule);
+ timetable.edit(idx, updatedSchedules);
+ Toast.makeText(requireContext(), "수업 정보가 수정되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onDelete() {
+ // 스티커 삭제
+ timetable.remove(idx);
+ Toast.makeText(requireContext(), "수업 정보가 삭제되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
+ classEditOrDeleteDialogFragment.show(requireActivity().getSupportFragmentManager(), "ClassEditDialog");
+ });
+
+ // 다음 버튼
Button signupNextButton = view.findViewById(R.id.btnNext);
signupNextButton.setFocusable(false);
signupNextButton.setOnClickListener(v -> {
- navController.navigate(R.id.actionMoveToLogin);
+ saveTimetableToFirestoreStructured();
+ saveTimetable();
+ navController.navigate(R.id.actionNextToSignupDone);
});
+ // 건너뛰기 버튼
Button signupSkipButton = view.findViewById(R.id.btnSkip);
signupSkipButton.setFocusable(false);
signupSkipButton.setOnClickListener(v -> {
- navController.navigate(R.id.actionMoveToLogin);
+ navController.navigate(R.id.actionSkipToSignupDone);
});
}
-}
+
+ private void addScheduleToTimetable(String className, String classPlace, int day, int startHour, int startMinute, int endHour, int endMinute) {
+ ArrayList schedules = new ArrayList<>();
+
+ Schedule schedule = new Schedule();
+ schedule.setClassTitle(className);
+ schedule.setClassPlace(classPlace);
+ schedule.setDay(day);
+ schedule.setStartTime(new Time(startHour, startMinute));
+ schedule.setEndTime(new Time(endHour, endMinute));
+
+ schedules.add(schedule);
+
+ timetable.add(schedules);
+ }
+
+ private void saveTimetable() {
+ SharedPreferences prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+
+ String json = timetable.createSaveData();
+ editor.putString(TIMETABLE_KEY, json);
+ editor.apply();
+
+ Toast.makeText(requireContext(), "시간표가 저장되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+
+ private void saveTimetableToFirestoreStructured() {
+ String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
+ String json = timetable.createSaveData();
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+
+ // Firestore에 저장
+ db.collection("users").document(userId)
+ .update(new HashMap() {{
+ put("timetableData", json);
+ }})
+ .addOnSuccessListener(aVoid -> {
+ Toast.makeText(requireContext(), "Firestore에 시간표가 저장되었습니다.", Toast.LENGTH_SHORT).show();
+ })
+ .addOnFailureListener(e -> {
+ Toast.makeText(requireContext(), "시간표 저장 실패: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ });
+
+ // 시간표 데이터를 가져오기
+ ArrayList schedules = timetable.getAllSchedulesInStickers();
+
+ for (Schedule schedule : schedules) {
+ HashMap scheduleMap = new HashMap<>();
+ scheduleMap.put("classTitle", schedule.getClassTitle());
+ scheduleMap.put("classPlace", schedule.getClassPlace());
+ scheduleMap.put("professorName", schedule.getProfessorName());
+ scheduleMap.put("day", schedule.getDay());
+ scheduleMap.put("startTime", new HashMap() {{
+ put("hour", schedule.getStartTime().getHour());
+ put("minute", schedule.getStartTime().getMinute());
+ }});
+ scheduleMap.put("endTime", new HashMap() {{
+ put("hour", schedule.getEndTime().getHour());
+ put("minute", schedule.getEndTime().getMinute());
+ }});
+
+ // Firestore에 저장
+ db.collection("users")
+ .document(userId)
+ .collection("timetable")
+ .add(scheduleMap)
+ .addOnSuccessListener(aVoid -> Log.d("Firestore", "수업 저장 성공"))
+ .addOnFailureListener(e -> Log.e("Firestore", "수업 저장 실패: " + e.getMessage()));
+ }
+
+ Toast.makeText(requireContext(), "Firestore에 시간표가 저장되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+
+ private void loadTimetableFromFirestoreStructured() {
+ String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
+//
+//
+// db에서 파싱한 data를 다시 json형식으로 합쳐서 표현하는 방법
+// db.collection("users")
+// .document(userId)
+// .collection("timetable")
+// .get()
+// .addOnSuccessListener(querySnapshot -> {
+// ArrayList schedules = new ArrayList<>();
+// querySnapshot.forEach(document -> {
+// HashMap data = (HashMap) document.getData();
+//
+// Schedule schedule = new Schedule();
+// schedule.setClassTitle((String) data.get("classTitle"));
+// schedule.setClassPlace((String) data.get("classPlace"));
+// schedule.setProfessorName((String) data.get("professorName"));
+// schedule.setDay(((Long) data.get("day")).intValue());
+//
+// HashMap startTime = (HashMap) data.get("startTime");
+// schedule.setStartTime(new Time(((Long) startTime.get("hour")).intValue(), ((Long) startTime.get("minute")).intValue()));
+//
+// HashMap endTime = (HashMap) data.get("endTime");
+// schedule.setEndTime(new Time(((Long) endTime.get("hour")).intValue(), ((Long) endTime.get("minute")).intValue()));
+//
+// schedules.add(schedule);
+// });
+//
+// // 시간표에 로드
+// timetable.add(schedules);
+// Toast.makeText(requireContext(), "Firestore에서 시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
+// })
+// .addOnFailureListener(e -> {
+// Toast.makeText(requireContext(), "시간표 불러오기 실패: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+// });
+
+// db에 json을 그냥 불러와서 사용하는 방법
+// db.collection("users")
+// .document(userId)
+// .get()
+// .addOnSuccessListener(documentSnapshot -> {
+// if (documentSnapshot.exists()) {
+// // 특정 필드 값 가져오기
+// String json = documentSnapshot.getString("timetableData"); // "name" 필드
+// // 사용
+// if (json != null) {
+// timetable.load(json);
+// //Toast.makeText(requireContext(), "저장된 시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
+// }
+// } else {
+// Log.d("Firestore", "Document does not exist.");
+// }
+// })
+// .addOnFailureListener(e -> {
+// Log.e("Firestore", "Error fetching document", e);
+// });
+// local에 저장하고 사용하는 방법
+// SharedPreferences prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+// String json = prefs.getString(TIMETABLE_KEY, null);
+//
+// if (json != null) {
+// timetable.load(json);
+// //Toast.makeText(requireContext(), "저장된 시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
+// }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/SignupDoneFragment.java b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/SignupDoneFragment.java
index 3b4efb0..77d3300 100644
--- a/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/SignupDoneFragment.java
+++ b/app/src/main/java/com/example/mohassu/LoginAndSignUpFragment/SignupDoneFragment.java
@@ -30,7 +30,7 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
Button signupNextButton = view.findViewById(R.id.btnGoToLogin);
signupNextButton.setFocusable(false);
signupNextButton.setOnClickListener(v -> {
- navController.navigate(R.id.btnGoToLogin);
+ navController.navigate(R.id.actionMoveToLogin);
});
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/MainFragment/EmptyBottomSheetProfile.java b/app/src/main/java/com/example/mohassu/MainFragment/EmptyBottomSheetProfile.java
new file mode 100644
index 0000000..ffa547a
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/MainFragment/EmptyBottomSheetProfile.java
@@ -0,0 +1,94 @@
+package com.example.mohassu.MainFragment;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+
+import com.bumptech.glide.Glide;
+import com.example.mohassu.R;
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.firestore.DocumentSnapshot;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.QueryDocumentSnapshot;
+
+public class EmptyBottomSheetProfile extends BottomSheetDialogFragment {
+
+ private static final String ARG_FRIEND_ID = "friend_id";
+ FirebaseAuth auth = FirebaseAuth.getInstance();
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ FirebaseUser currentUser = auth.getCurrentUser();
+
+ public static EmptyBottomSheetProfile newInstance(String friendId) {
+ EmptyBottomSheetProfile fragment = new EmptyBottomSheetProfile();
+ Bundle args = new Bundle();
+ args.putString(ARG_FRIEND_ID, friendId); // 데이터를 Bundle에 넣어서 전달
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_bottom_sheet_check_profile, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ ImageButton closeButton = view.findViewById(R.id.btn_close);
+ if (closeButton != null) {
+ closeButton.setOnClickListener(v -> dismiss());
+ }
+
+ String friendId = getArguments() != null ? getArguments().getString(ARG_FRIEND_ID) : null;
+
+ if (currentUser != null) {
+ String uid = currentUser.getUid();
+
+ db.collection("users").document(uid)
+ .collection("friends").document(friendId)
+ .get()
+ .addOnSuccessListener(documentSnapshot -> {
+ if (documentSnapshot.exists()) {
+ String nickName = documentSnapshot.getString("nickname");
+ String name = documentSnapshot.getString("name");
+ String photoUrl = documentSnapshot.getString("photoUrl");
+
+ // UI 업데이트
+ TextView textNickname = view.findViewById(R.id.text_nickname);
+ TextView textName = view.findViewById(R.id.text_name);
+ ImageView profileImage = view.findViewById(R.id.img_profile);
+
+ textNickname.setText(nickName != null ? nickName : "#nickname");
+ textName.setText(name != null ? name : "#name");
+
+ // 프로필 사진 로드
+ if (photoUrl != null) {
+ Glide.with(this)
+ .load(photoUrl)
+ .placeholder(R.drawable.img_default)
+ .error(R.drawable.img_default)
+ .into(profileImage);
+ } else {
+ profileImage.setImageResource(R.drawable.pic_basic_profile);
+ }
+ } else {
+ Toast.makeText(getContext(), "친구 정보를 찾을 수 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/MainFragment/MainFriendListFragment.java b/app/src/main/java/com/example/mohassu/MainFragment/MainFriendListFragment.java
index 8423def..87fe858 100644
--- a/app/src/main/java/com/example/mohassu/MainFragment/MainFriendListFragment.java
+++ b/app/src/main/java/com/example/mohassu/MainFragment/MainFriendListFragment.java
@@ -1,32 +1,175 @@
package com.example.mohassu.MainFragment;
import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.EditText;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.example.mohassu.CheckProfileBottomSheetFragment;
+import com.example.mohassu.DialogFragment.AddFriendDialogFragment;
import com.example.mohassu.R;
+import com.example.mohassu.adapters.FriendAdapter;
+import com.example.mohassu.models.Friend;
+import com.example.mohassu.models.ScheduleClass;
+import com.example.mohassu.models.Time;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.DocumentSnapshot;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.QueryDocumentSnapshot;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
public class MainFriendListFragment extends Fragment {
+
+ private RecyclerView friendRecyclerView;
+ private FriendAdapter friendAdapter;
+ private List friendList = new ArrayList<>();
+ private EditText etSearchFriend;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main_friend_list, container, false);
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- // NavController 초기화
NavController navController = Navigation.findNavController(view);
- // 뒤로가기 버튼에 클릭 리스너 추가
- view.findViewById(R.id.btnBack).setOnClickListener(v -> {
- navController.navigateUp();
+ // 뒤로가기 버튼
+ view.findViewById(R.id.btnBack).setOnClickListener(v -> navController.navigateUp());
+
+ // 친구 추가 버튼
+ view.findViewById(R.id.add_friend_button).setOnClickListener(v -> {
+ AddFriendDialogFragment dialog = new AddFriendDialogFragment();
+ dialog.show(getParentFragmentManager(), "AddFriendDialog");
+ });
+
+ etSearchFriend = view.findViewById(R.id.etSearchFriend);
+ friendRecyclerView = view.findViewById(R.id.friendRecyclerView);
+ friendRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
+
+ friendAdapter = new FriendAdapter(requireContext(), friendList, this::showCheckProfileBottomSheet);
+ friendRecyclerView.setAdapter(friendAdapter);
+
+ fetchFriends();
+
+ etSearchFriend.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ friendAdapter.filter(s.toString());
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {}
});
}
-}
+
+ private void fetchFriends() {
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
+
+ db.collection("users").document(currentUserId).collection("friends")
+ .get()
+ .addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ friendList.clear();
+ for (DocumentSnapshot document : task.getResult()) {
+ String friendUid = document.getId();
+ fetchFriendDetails(friendUid);
+ }
+ } else {
+ Log.e("fetchFriend", "친구 목록을 불러오는 중 오류 발생");
+ }
+ });
+ }
+
+ private void fetchFriendDetails(String friendUid) {
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+
+ db.collection("users").document(friendUid)
+ .get()
+ .addOnSuccessListener(documentSnapshot -> {
+ if (documentSnapshot.exists()) {
+ String name = documentSnapshot.getString("name");
+ String email = documentSnapshot.getString("email");
+ String nickname = documentSnapshot.getString("nickname");
+ String statusMessage = documentSnapshot.getString("statusMessage");
+ String photoUrl = documentSnapshot.getString("photoUrl");
+
+ fetchCurrentClass(friendUid, currentClass -> {
+ friendList.add(new Friend(friendUid, name, nickname, email, statusMessage, photoUrl, currentClass));
+ friendAdapter.setData(friendList);
+ });
+ }
+ })
+ .addOnFailureListener(e -> Log.e("fetchFriendDetails", "프로필 불러오기 실패: " + e.getMessage()));
+ }
+
+ private void fetchCurrentClass(String friendUid, CurrentClassCallback callback) {
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+
+ db.collection("users").document(friendUid).collection("timeTable")
+ .get()
+ .addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ Calendar calendar = Calendar.getInstance();
+ int today = calendar.get(Calendar.DAY_OF_WEEK) - 1;
+ int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
+ int currentMinute = calendar.get(Calendar.MINUTE);
+
+ ScheduleClass currentClass = null;
+
+ for (QueryDocumentSnapshot document : task.getResult()) {
+ int day = document.getLong("day").intValue();
+ int startHour = document.getLong("startTime.hour").intValue();
+ int startMinute = document.getLong("startTime.minute").intValue();
+ int endHour = document.getLong("endTime.hour").intValue();
+ int endMinute = document.getLong("endTime.minute").intValue();
+
+ if (today == day &&
+ (currentHour > startHour || (currentHour == startHour && currentMinute >= startMinute)) &&
+ (currentHour < endHour || (currentHour == endHour && currentMinute <= endMinute))) {
+ currentClass = new ScheduleClass(
+ document.getString("classTitle"),
+ document.getString("classPlace"),
+ document.getString("professorName"),
+ day,
+ new Time(startHour, startMinute),
+ new Time(endHour, endMinute)
+ );
+ break;
+ }
+ }
+ callback.onClassFetched(currentClass);
+ }
+ });
+ }
+
+ interface CurrentClassCallback {
+ void onClassFetched(ScheduleClass currentClass);
+ }
+
+ public void showCheckProfileBottomSheet(Friend friend) {
+ CheckProfileBottomSheetFragment bottomSheet = CheckProfileBottomSheetFragment.newInstance(friend);
+ bottomSheet.show(getParentFragmentManager(), "CheckProfileBottomSheet");
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/MainFragment/MainHomeFragment.java b/app/src/main/java/com/example/mohassu/MainFragment/MainHomeFragment.java
index 8a42f51..7e8c678 100644
--- a/app/src/main/java/com/example/mohassu/MainFragment/MainHomeFragment.java
+++ b/app/src/main/java/com/example/mohassu/MainFragment/MainHomeFragment.java
@@ -1,62 +1,653 @@
package com.example.mohassu.MainFragment;
+import static com.naver.maps.map.CameraUpdate.REASON_GESTURE;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.location.Location;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.FrameLayout;
import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
+import com.bumptech.glide.Glide;
+import com.example.mohassu.Constants;
+import com.example.mohassu.PlaceInfo;
import com.example.mohassu.R;
+import com.google.android.gms.location.GeofencingClient;
+import com.google.android.gms.location.LocationServices;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.firestore.FieldValue;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.GeoPoint;
+import com.google.firebase.firestore.QueryDocumentSnapshot;
+import com.google.firebase.storage.FirebaseStorage;
+import com.google.firebase.storage.StorageReference;
+import com.naver.maps.geometry.LatLng;
+import com.naver.maps.map.CameraAnimation;
+import com.naver.maps.map.CameraUpdate;
+import com.naver.maps.map.LocationTrackingMode;
+import com.naver.maps.map.MapFragment;
+import com.naver.maps.map.NaverMap;
+import com.naver.maps.map.OnMapReadyCallback;
+import com.naver.maps.map.overlay.LocationOverlay;
+import com.naver.maps.map.overlay.Marker;
+import com.naver.maps.map.overlay.OverlayImage;
+import com.naver.maps.map.util.FusedLocationSource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MainHomeFragment extends Fragment implements OnMapReadyCallback {
-public class MainHomeFragment extends Fragment {
+ private NaverMap naverMap;
+ private FusedLocationSource locationSource;
+ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1000;
+ private boolean isCameraMovedByUser = false;
+ private boolean isMyMarkerClicked = false; // 마커 클릭 상태 추적 변수
+ private boolean isFriendMarkerClicked = false;
+ private boolean isFocusMode = false;
+ private boolean isEditTextClicked = false;
+ private boolean isPlaceFound = false;
+ ImageButton notificationButton;
+ ImageButton promiseListButton;
+ ImageButton signupNextButton;
+ ImageButton createPromiseButton;
+ ImageButton myPageButton;
+ ImageButton myLocationButton;
+ TextView tvBuildingName;
+ Marker locationMarker;
+
+ FirebaseAuth auth = FirebaseAuth.getInstance();
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ FirebaseUser currentUser = auth.getCurrentUser();
+
+ // ActivityResultLauncher for permission requests
+ private final ActivityResultLauncher requestPermissionLauncher =
+ registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
+ if (isGranted) {
+ if (naverMap != null) {
+ naverMap.setLocationTrackingMode(LocationTrackingMode.Follow);
+ }
+ } else {
+ Toast.makeText(requireContext(), "위치 권한이 거부되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main_home, container, false);
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ Toast.makeText(requireContext(), "지도를 불러오는 중입니다... \n화면을 누르지 마십시오", Toast.LENGTH_LONG).show();
+ // Initialize MapFragment
+ MapFragment mapFragment = (MapFragment) getChildFragmentManager().findFragmentById(R.id.fragment_map);
+ if (mapFragment == null) {
+ mapFragment = MapFragment.newInstance();
+ getChildFragmentManager().beginTransaction().add(R.id.fragment_map, mapFragment).commit();
+ }
+ mapFragment.getMapAsync(this);
+
+ // Initialize LocationSource
+ locationSource = new FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE);
+
+ GeofencingClient geofencingClient = LocationServices.getGeofencingClient(requireContext());
+
+ // Custom button to center on current location
+ myLocationButton = view.findViewById(R.id.btnNowLocation);
+ if (myLocationButton != null) {
+ myLocationButton.setOnClickListener(v -> {
+ isCameraMovedByUser = false; // 자동 중심 이동 다시 활성화
+ LatLng currentPosition = naverMap.getLocationOverlay().getPosition();
+ if (currentPosition != null) {
+ // Move camera to the current position
+ naverMap.moveCamera(CameraUpdate.scrollTo(currentPosition));
+ } else { // 예외처리 생략 가능
+ Toast.makeText(requireContext(), "현재 위치를 찾을 수 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
// NavController 초기화
NavController navController = Navigation.findNavController(view);
// 다음 프레그먼트를 클릭 시 다음 Fragment로 이동
// 알림 페이지 이동
- ImageButton notificationButton = view.findViewById(R.id.btnNotification);
+ notificationButton = view.findViewById(R.id.btnNotification);
notificationButton.setFocusable(false);
notificationButton.setOnClickListener(v -> {
navController.navigate(R.id.actionNotification);
});
// 약속 리스트 페이지 이동
- ImageButton promiseListButton = view.findViewById(R.id.btnPromiseList);
+ promiseListButton = view.findViewById(R.id.btnPromiseList);
promiseListButton.setFocusable(false);
promiseListButton.setOnClickListener(v -> {
navController.navigate(R.id.actionPromiseList);
});
// 친구 리스트 페이지 이동
- ImageButton signupNextButton = view.findViewById(R.id.btnFriendList);
+ signupNextButton = view.findViewById(R.id.btnFriendList);
signupNextButton.setFocusable(false);
signupNextButton.setOnClickListener(v -> {
navController.navigate(R.id.actionFriendList);
});
//약속 추가 페이지 이동
- ImageButton createPromiseButton = view.findViewById(R.id.btnAddPlan);
+ createPromiseButton = view.findViewById(R.id.btnAddPlan);
createPromiseButton.setFocusable(false);
createPromiseButton.setOnClickListener(v -> {
navController.navigate(R.id.actionAddPlan);
});
// 마이페이지 이동
- ImageButton myPageButton = view.findViewById(R.id.btnMyPage);
+ myPageButton = view.findViewById(R.id.btnMyPage);
myPageButton.setFocusable(false);
myPageButton.setOnClickListener(v -> {
navController.navigate(R.id.actionMyPage);
});
}
-}
+
+ @Override
+ public void onMapReady(@NonNull NaverMap naverMap) {
+ this.naverMap = naverMap;
+
+ // 현재 위치 불러오기 전 초기 화면을 보이지 않는 위치(바다)로 설정
+ CameraUpdate initialUpdate = CameraUpdate.scrollTo(new LatLng(0, 0));
+ naverMap.moveCamera(initialUpdate);
+
+ // 위치 정보 가져오기
+ naverMap.setLocationSource(locationSource);
+
+ // +- 줌컨트롤 버튼 비활성화
+ naverMap.getUiSettings().setZoomControlEnabled(false);
+
+
+ // 위치 요청 수락 시 트래킹모드 가동, 거부 시 다시 묻기
+ if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ naverMap.setLocationTrackingMode(LocationTrackingMode.Follow);// 트래킹 모드 설정 후 나중에 오버레이 비활성화
+ } else {
+ requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);
+ }
+
+ // 지도 드래그 이벤트 설정
+ naverMap.addOnCameraChangeListener((reason, animated) -> {
+ if (reason == REASON_GESTURE) {
+ isCameraMovedByUser = true; // 사용자가 화면을 이동했을 때 플래그 설정
+ isMyMarkerClicked = false; // 사용자가 화면을 이동하면 마커 클릭 상태 해제
+ isFriendMarkerClicked = false;
+
+ if (isFocusMode) {
+ resetMarkerFocusMode();
+ }
+ FrameLayout mapContainer = requireActivity().findViewById(R.id.fragment_map);
+ View myBalloonView = mapContainer.findViewById(R.id.dialog_edit_message); // ID로 찾기
+ if (myBalloonView != null) {
+ mapContainer.removeView(myBalloonView); // 내 말풍선 제거
+ }
+ View friendBalloonView = mapContainer.findViewById(R.id.dialog_text_message); // ID로 찾기
+ if (friendBalloonView != null) {
+ mapContainer.removeView(friendBalloonView); // 친구 말풍선 제거
+ }
+ View bannerView = mapContainer.findViewById(R.id.fragment_status_banner); // ID로 찾기
+ if (bannerView != null) {
+ mapContainer.removeView(bannerView); // 친구 상태 배너 제거
+ }
+ View profileButton = mapContainer.findViewById(R.id.dialog_show_profile); // ID로 찾기
+ if (profileButton != null) {
+ mapContainer.removeView(profileButton); // 친구 프로필 확인 버튼 제거
+ }
+ }
+ });
+
+ // 내 Marker 초기화
+ initializeMyMarker();
+
+ // 친구 Marker 초기화 및 위치 갱신
+ loadFriendMarkers();
+
+ // 지도 클릭 이벤트 설정 (말풍선 닫기)
+ naverMap.setOnMapClickListener((point, coord) -> {
+ if (!isEditTextClicked) {
+ isMyMarkerClicked = false; // 사용자가 화면을 클릭하면 마커 클릭 상태 해제
+ isFriendMarkerClicked = false;
+ if (isFocusMode) {
+ resetMarkerFocusMode();
+ }
+ FrameLayout mapContainer = requireActivity().findViewById(R.id.fragment_map);
+ View myBalloonView = mapContainer.findViewById(R.id.dialog_edit_message); // ID로 찾기
+ if (myBalloonView != null) {
+ mapContainer.removeView(myBalloonView); // 말풍선 제거
+ }
+ View friendBalloonView = mapContainer.findViewById(R.id.dialog_text_message); // ID로 찾기
+ if (friendBalloonView != null) {
+ mapContainer.removeView(myBalloonView); // 말풍선 제거
+ }
+ View bannerView = mapContainer.findViewById(R.id.fragment_status_banner); // ID로 찾기
+ if (bannerView != null) {
+ mapContainer.removeView(bannerView); // 말풍선 제거
+ }
+ View profileButton = mapContainer.findViewById(R.id.dialog_show_profile); // ID로 찾기
+ if (profileButton != null) {
+ mapContainer.removeView(profileButton); // 말풍선 제거
+ }
+ }
+ });
+
+
+ // 위치 변화 업데이트
+ naverMap.addOnLocationChangeListener(location -> {
+ if (locationMarker == null) {
+ // locationMarker가 초기화되지 않았다면 초기화 기다리기
+ return;
+ }
+ updateUserLocationToFirestore(location);
+ loadUserLocationFromFirestore();
+ naverMap.getLocationOverlay().setVisible(false); // 오버레이 비활성화
+ });
+
+ }
+
+ private void initializeMyMarker() {
+ CameraUpdate hide = CameraUpdate.scrollAndZoomTo(new LatLng(0,0), 20.0)
+ .animate(CameraAnimation.Easing);
+ naverMap.moveCamera(hide); // 가끔씩 naverMap 로딩 버그로 인해 위치 업데이트 이후 보이게 설정
+
+ // XML 레이아웃을 Inflate
+ View myMarkerView = LayoutInflater.from(requireContext()).inflate(R.layout.my_marker, null);
+ ImageView myProfile = myMarkerView.findViewById(R.id.my_marker_image);
+
+ if (currentUser != null) {
+ String uid = currentUser.getUid();
+
+ // Firestore에서 사용자 데이터를 가져옴
+ db.collection("users").document(currentUser.getUid()) // 예: 사용자 ID를 문서 ID로 사용
+ .get()
+ .addOnSuccessListener(documentSnapshot -> {
+ if (documentSnapshot.exists()) {
+ String photoUrl = documentSnapshot.getString("photoUrl");
+
+ if (photoUrl != null) {
+ // Glide를 사용하여 이미지 로드
+ Glide.with(this)
+ .load(photoUrl)
+ .placeholder(R.drawable.img_default)
+ .error(R.drawable.img_default)
+ .into(myProfile);
+
+ } else {
+ myProfile.setImageResource(R.drawable.pic_basic_profile); // 기본 이미지
+ }
+ // View를 Bitmap으로 변환
+ //Bitmap myMarkerBitmap = convertViewToBitmap(myMarkerView);
+// Marker 객체 생성
+ locationMarker = new Marker();
+ locationMarker.setPosition(naverMap.getLocationOverlay().getPosition());
+ locationMarker.setIcon(OverlayImage.fromResource(R.drawable.img_marker_red)); // 마커 이미지 설정
+ locationMarker.setWidth(120); // 마커 크기 조정
+ locationMarker.setHeight(140);
+ locationMarker.setMap(naverMap); // 지도에 마커 추가
+
+ locationMarker.setOnClickListener(overlay -> {
+
+ if (naverMap == null) { // 테스트 필요
+ Toast.makeText(requireContext(), "지도를 불러오는 중입니다. 잠시만 기다려주세요.", Toast.LENGTH_SHORT).show();
+ return true;
+ }
+
+ //다른 버튼 안 보이게
+ showMarkerFocusMode();
+
+ LatLng location = locationMarker.getPosition();
+
+ // 현재 위치 가져오기
+ CameraUpdate update = CameraUpdate.scrollAndZoomTo(location, 20.0)
+ .animate(CameraAnimation.Easing);
+ naverMap.moveCamera(update);
+ isMyMarkerClicked = true;
+ isFriendMarkerClicked = false;
+
+
+ FrameLayout mapContainer = requireActivity().findViewById(R.id.fragment_map);
+
+ // 말풍선 View 인플레이트
+ View myBalloonView = LayoutInflater.from(requireContext())
+ .inflate(R.layout.dialog_edit_message, mapContainer, false);
+ mapContainer.addView(myBalloonView); // 말풍선 추가
+
+ // EditText 참조 가져오기
+ EditText markerMessageEditText = myBalloonView.findViewById(R.id.markerMyMessage);
+
+ db.collection("users")
+ .document(currentUser.getUid()) // 사용자 ID
+ .get()
+ .addOnSuccessListener(statusMsg -> {
+ if (statusMsg.exists()) {
+ // 상태 메시지가 이미 저장되어 있으면 EditText에 띄우기
+ String storedMessage = statusMsg.getString("statusMessage");
+ if (storedMessage != null && !storedMessage.isEmpty()) {
+ markerMessageEditText.setText(storedMessage); // 기존 메시지 띄우기
+ }
+ }
+ })
+ .addOnFailureListener(e -> {
+ Log.w("TAG", "Error getting document", e);
+ });
+
+ markerMessageEditText.setOnEditorActionListener((v, actionId, event) -> {
+ isEditTextClicked = true;
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ String statusMessage = markerMessageEditText.getText().toString().trim();
+
+ if (!statusMessage.isEmpty()) {
+ db.collection("users")
+ .document(currentUser.getUid()) // 사용자 ID
+ .update("statusMessage", statusMessage)
+ .addOnSuccessListener(aVoid -> {
+ // 저장 성공 시 처리 (예: 메시지 표시)
+ Toast.makeText(requireContext(), "상태 메시지가 업데이트되었습니다.", Toast.LENGTH_SHORT).show();
+ });
+ }
+
+
+ InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
+ markerMessageEditText.clearFocus(); // 포커스 해제하여 깜빡임 끄기
+ }
+ return true;
+ }
+ return false;
+ });
+ return true; // 클릭 이벤트 소비
+ });
+ }
+ });
+ }
+ }
+
+ private void updateUserLocationToFirestore(Location location) {
+ if (currentUser == null) return; // 사용자 인증되지 않은 경우
+
+ String uid = currentUser.getUid(); // 사용자 고유 ID (UID)
+
+ //GeoPoint로 location 저장
+ GeoPoint geoPoint = new GeoPoint(location.getLatitude(), location.getLongitude());
+
+ // Firestore에 저장할 데이터
+ Map locationData = new HashMap<>();
+ locationData.put("location", geoPoint);
+ locationData.put("timestamp", FieldValue.serverTimestamp()); // 서버의 타임스탬프 추가
+
+ db.collection("users")
+ .document(uid)
+ .collection("location")
+ .document("currentLocation")
+ .set(locationData) // 🔥 Firestore에 데이터 저장
+ .addOnSuccessListener(aVoid -> Log.d("TAG", "Location updated in Firestore"))
+ .addOnFailureListener(e -> Log.w("TAG", "Failed to update location", e));
+ }
+
+ private void loadUserLocationFromFirestore() {
+ if (currentUser == null) return; // 사용자 인증되지 않은 경우
+
+ String uid = currentUser.getUid();
+
+ db.collection("users")
+ .document(uid)
+ .collection("location")
+ .document("currentLocation")
+ .addSnapshotListener((snapshot, error) -> {
+ if (error != null) {
+ Log.w("TAG", "Listen failed.", error);
+ return;
+ }
+
+ if (snapshot != null && snapshot.exists()) {
+ GeoPoint newGeopoint = snapshot.getGeoPoint("location");
+
+ LatLng newLocation = new LatLng(newGeopoint.getLatitude(), newGeopoint.getLongitude());
+
+ // 사용자 위치 업데이트
+ locationMarker.setPosition(newLocation);
+
+ // 마커 클릭 상태 또는 초기 화면에서 카메라 이동
+ if (isMyMarkerClicked) {
+ CameraUpdate update = CameraUpdate.scrollTo(newLocation)
+ .animate(CameraAnimation.Easing); // 줌 레벨 17.0
+ naverMap.moveCamera(update);
+ } else if (!isCameraMovedByUser && !isFriendMarkerClicked) {
+ CameraUpdate update = CameraUpdate.scrollAndZoomTo(newLocation, 17.0)
+ .animate(CameraAnimation.Easing);
+ naverMap.moveCamera(update);
+ }
+
+
+ View view = getView();
+ tvBuildingName = view.findViewById(R.id.tvBuildingName);
+
+ loadFromGeofencing(newLocation);
+ }
+ });
+ }
+
+
+ private void loadFromGeofencing(LatLng location) {
+ for (PlaceInfo place : Constants.PLACES) {
+ float[] results = new float[1];
+ Location.distanceBetween(
+ location.latitude, location.longitude,
+ place.getLocation().latitude, place.getLocation().longitude,
+ results
+ );
+
+ if (results[0] <= place.getRadius()) {
+ String buildingName = place.getName();
+ tvBuildingName.setText(buildingName + "에 있어요.");
+ if (!isFocusMode) {
+ tvBuildingName.setVisibility(View.VISIBLE);
+ }
+ db.collection("users")
+ .document(currentUser.getUid())
+ .update("place", buildingName) // Firestore에 장소명 저장
+ .addOnSuccessListener(aVoid -> Log.d("TAG", "Location updated in Firestore"))
+ .addOnFailureListener(e -> Log.w("TAG", "Failed to update location", e));
+ break; // 반경 내 첫 번째 장소를 찾으면 종료
+ }
+ }
+ tvBuildingName.setVisibility(View.GONE); // 반경 내 장소가 없을 경우
+
+ if (!isPlaceFound) {
+ db.collection("users")
+ .document(currentUser.getUid())
+ .update("place", "지도 위 장소")
+ .addOnSuccessListener(aVoid -> Log.d("TAG", "No place found, updated to '건물없음'"))
+ .addOnFailureListener(e -> Log.w("TAG", "Failed to update location to '건물없음'", e));
+ }
+ }
+
+ // Firestore에서 친구 데이터 가져오기
+ private void loadFriendMarkers() {
+//
+// // XML 레이아웃을 Inflate
+// View friendMarkerView = LayoutInflater.from(requireContext()).inflate(R.layout.your_marker, null);
+// ImageView friendProfile = friendMarkerView.findViewById(R.id.your_marker_image);
+//
+// if (currentUser != null) {
+// String uid = currentUser.getUid();
+//
+// db.collection("users").document(uid)
+// .collection("friends")
+// .get()
+// .addOnSuccessListener(querySnapshot -> {
+// if (querySnapshot.isEmpty()) {
+// // 친구 데이터가 없을 경우 처리
+// Toast.makeText(requireContext(), "친구를 추가해보세요!", Toast.LENGTH_SHORT).show();
+// return;
+// }
+//
+// for (QueryDocumentSnapshot document : querySnapshot) {
+// String name = document.getString("name");
+// String nickname = document.getString("nickname");
+// String class_name = document.getString("class_name");
+// String place = document.getString("place");
+// String startTime = document.getString("startTime");
+// String endTime = document.getString("endTime");
+// String photoUrl = document.getString("photoUrl");
+// GeoPoint location = document.getGeoPoint("location");
+// String statusMessage = document.getString("statusMessage");
+// // 마커 클릭 시 친구 ID 전달
+// String friendId = document.getId();
+//
+// if (photoUrl != null) {
+// // Glide를 사용하여 이미지 로드
+// Glide.with(this)
+// .load(photoUrl)
+// .placeholder(R.drawable.img_default)
+// .error(R.drawable.img_default)
+// .into(friendProfile);
+// } else {
+// friendProfile.setImageResource(R.drawable.pic_basic_profile); // 기본 이미지
+// }
+//
+// // View를 Bitmap으로 변환
+// Bitmap friendMarkerBitmap = convertViewToBitmap(friendMarkerView);
+//
+// // 친구 위치를 기반으로 마커 추가
+//
+// LatLng friendLocation = new LatLng(location.getLatitude(), location.getLongitude());
+//
+// Marker friendMarker = new Marker();
+// friendMarker.setPosition(friendLocation);
+// friendMarker.setIcon(OverlayImage.fromBitmap(friendMarkerBitmap)); // 마커 이미지
+// friendMarker.setWidth(120);
+// friendMarker.setHeight(140);
+// friendMarker.setMap(naverMap);
+//
+// // 마커 클릭 이벤트
+// friendMarker.setOnClickListener(overlay -> { // 아직 테스트
+// // 클릭 이벤트 설정
+// if (naverMap == null || getView() == null) {
+// // 지도 초기화가 완료되지 않은 경우
+// Toast.makeText(requireContext(), "지도가 아직 초기화되지 않았습니다.", Toast.LENGTH_SHORT).show();
+// return true; // 이벤트 소비
+// }
+//
+// //다른 버튼 안 보이게
+// showMarkerFocusMode();
+//
+// //친구 위치로 카메라 업데이트
+// CameraUpdate update = CameraUpdate.scrollAndZoomTo(friendLocation, 20.0)
+// .animate(CameraAnimation.Easing);
+// naverMap.moveCamera(update);
+// isFriendMarkerClicked = true;
+// isMyMarkerClicked = false;
+//
+// FrameLayout mapContainer = requireActivity().findViewById(R.id.fragment_map);
+//
+// // 말풍선 View 인플레이트
+// View friendBalloonView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_text_message, mapContainer, false);
+// TextView friendBalloonText = friendBalloonView.findViewById(R.id.markerFriendMessage);
+// friendBalloonText.setText(statusMessage);
+// mapContainer.addView(friendBalloonView); // 말풍선 추가
+//
+// // 배너 View 인플레이트
+// View bannerView = LayoutInflater.from(requireContext()).inflate(R.layout.fragment_status_banner, mapContainer, false);
+// mapContainer.addView(bannerView);
+//
+// // UI 업데이트
+// updateStatusBanner(place, class_name, startTime, endTime);
+//
+// // 프로필버튼 View 인플레이트
+// View profileButton = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_show_profile, mapContainer, false);
+// mapContainer.addView(profileButton);
+// // 클릭 이벤트 설정
+// // 프로필 보기 버튼 클릭 이벤트
+// profileButton.findViewById(R.id.showProfileButton).setOnClickListener(v -> {
+// // BottomSheetDialogFragment 호출
+// EmptyBottomSheetProfile bottomSheet = EmptyBottomSheetProfile.newInstance(friendId);
+// bottomSheet.show(getParentFragmentManager(), "ProfileBottomSheet");
+// });
+//
+// return true; // 클릭 이벤트 소비
+// });
+// }
+// });
+// }
+ }
+
+ // 상태 배너 업데이트 메서드
+ private void updateStatusBanner(String place, String class_name, String startTime, String endTime) {
+ View view = getView();
+ if (view == null) return;
+
+ TextView placeInfo = view.findViewById(R.id.placeInfo);
+ TextView classInfo = view.findViewById(R.id.classInfo);
+ TextView stTimeInfo = view.findViewById(R.id.startTimeInfo);
+ TextView endTimeInfo = view.findViewById(R.id.endTimeInfo);
+
+ // Firestore 데이터로 텍스트 업데이트
+ placeInfo.setText(place != null ? place : "#PLACE");
+ //classInfo.setText(class_name != null ? class_name : "#CLASS");
+ //stTimeInfo.setText(startTime != null ? startTime : "#st_time");
+ //endTimeInfo.setText(endTime != null ? endTime : "#end_time");
+ }
+
+ private void showMarkerFocusMode() {
+ // 버튼 숨기기
+ isFocusMode = true;
+ notificationButton.setVisibility(View.GONE);
+ promiseListButton.setVisibility(View.GONE);
+ signupNextButton.setVisibility(View.GONE);
+ createPromiseButton.setVisibility(View.GONE);
+ myPageButton.setVisibility(View.GONE);
+ myLocationButton.setVisibility(View.GONE);
+ tvBuildingName.setVisibility(View.GONE);
+ }
+
+
+ private void resetMarkerFocusMode() {
+ // 버튼 다시 표시
+ isFocusMode = false;
+ notificationButton.setVisibility(View.VISIBLE);
+ promiseListButton.setVisibility(View.VISIBLE);
+ signupNextButton.setVisibility(View.VISIBLE);
+ createPromiseButton.setVisibility(View.VISIBLE);
+ myPageButton.setVisibility(View.VISIBLE);
+ myLocationButton.setVisibility(View.VISIBLE);
+ tvBuildingName.setVisibility(View.VISIBLE);
+ }
+
+ private Bitmap convertViewToBitmap(View view) {
+ view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
+
+ Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ view.draw(canvas);
+
+ return bitmap;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/MainFragment/MainHomeFriendTestFragment.java b/app/src/main/java/com/example/mohassu/MainFragment/MainHomeFriendTestFragment.java
new file mode 100644
index 0000000..8631496
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/MainFragment/MainHomeFriendTestFragment.java
@@ -0,0 +1,356 @@
+package com.example.mohassu.MainFragment;
+
+import static com.naver.maps.map.CameraUpdate.REASON_GESTURE;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.location.Location;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+
+import com.example.mohassu.CheckProfileAndTimeTableFragment.BottomSheetCheckProfileFragment;
+import com.example.mohassu.Constants;
+import com.example.mohassu.PlaceInfo;
+import com.example.mohassu.R;
+import com.google.android.gms.location.GeofencingClient;
+import com.google.android.gms.location.LocationServices;
+import com.naver.maps.geometry.LatLng;
+import com.naver.maps.map.CameraAnimation;
+import com.naver.maps.map.CameraUpdate;
+import com.naver.maps.map.LocationTrackingMode;
+import com.naver.maps.map.MapFragment;
+import com.naver.maps.map.NaverMap;
+import com.naver.maps.map.OnMapReadyCallback;
+import com.naver.maps.map.Projection;
+import com.naver.maps.map.overlay.LocationOverlay;
+import com.naver.maps.map.overlay.Marker;
+import com.naver.maps.map.overlay.OverlayImage;
+import com.naver.maps.map.util.FusedLocationSource;
+
+public class MainHomeFriendTestFragment extends Fragment implements OnMapReadyCallback {
+
+ private NaverMap naverMap;
+ private FusedLocationSource locationSource;
+ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1000;
+ private Marker locationMarker; // Marker 객체 선언
+ private boolean isCameraMovedByUser = false;
+ private boolean isMarkerClicked = false; // 마커 클릭 상태 추적 변수
+
+ ImageButton notificationButton;
+ ImageButton promiseListButton;
+ ImageButton signupNextButton;
+ ImageButton createPromiseButton;
+ ImageButton myPageButton;
+ ImageButton myLocationButton;
+ TextView tvBuildingName;
+ boolean focusMode = false;
+
+ private GeofencingClient geofencingClient;
+
+ // ActivityResultLauncher for permission requests
+ private final ActivityResultLauncher requestPermissionLauncher =
+ registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
+ if (isGranted) {
+ if (naverMap != null) {
+ naverMap.setLocationTrackingMode(LocationTrackingMode.Follow);
+ }
+ } else {
+ Toast.makeText(requireContext(), "위치 권한이 거부되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_main_home, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ // Initialize MapFragment
+ MapFragment mapFragment = (MapFragment) getChildFragmentManager().findFragmentById(R.id.fragment_map);
+ if (mapFragment == null) {
+ mapFragment = MapFragment.newInstance();
+ getChildFragmentManager().beginTransaction().add(R.id.fragment_map, mapFragment).commit();
+ }
+ mapFragment.getMapAsync(this);
+
+ // Initialize LocationSource
+ locationSource = new FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE);
+
+ geofencingClient = LocationServices.getGeofencingClient(requireContext());
+
+ // Custom button to center on current location
+ myLocationButton = view.findViewById(R.id.btnNowLocation);
+ if (myLocationButton != null) {
+ myLocationButton.setOnClickListener(v -> {
+ isCameraMovedByUser = false; // 자동 중심 이동 다시 활성화
+ LatLng currentPosition = naverMap.getLocationOverlay().getPosition();
+ if (currentPosition != null) {
+ // Move camera to the current position
+ naverMap.moveCamera(CameraUpdate.scrollTo(currentPosition));
+ } else { // 예외처리 생략 가능
+ Toast.makeText(requireContext(), "현재 위치를 찾을 수 없습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ // NavController 초기화
+ //NavController navController = Navigation.findNavController(view);
+
+ // 다음 프레그먼트를 클릭 시 다음 Fragment로 이동
+ // 알림 페이지 이동
+ notificationButton = view.findViewById(R.id.btnNotification);
+ notificationButton.setFocusable(false);
+ notificationButton.setOnClickListener(v -> {
+ //navController.navigate(R.id.actionNotification);
+ });
+ // 약속 리스트 페이지 이동
+ promiseListButton = view.findViewById(R.id.btnPromiseList);
+ promiseListButton.setFocusable(false);
+ promiseListButton.setOnClickListener(v -> {
+ //navController.navigate(R.id.actionPromiseList);
+ });
+ // 친구 리스트 페이지 이동
+ signupNextButton = view.findViewById(R.id.btnFriendList);
+ signupNextButton.setFocusable(false);
+ signupNextButton.setOnClickListener(v -> {
+ //navController.navigate(R.id.actionFriendList);
+ });
+ //약속 추가 페이지 이동
+ createPromiseButton = view.findViewById(R.id.btnAddPlan);
+ createPromiseButton.setFocusable(false);
+ createPromiseButton.setOnClickListener(v -> {
+ //navController.navigate(R.id.actionAddPlan);
+ });
+ // 마이페이지 이동
+ myPageButton = view.findViewById(R.id.btnMyPage);
+ myPageButton.setFocusable(false);
+ myPageButton.setOnClickListener(v -> {
+ //navController.navigate(R.id.actionMyPage);
+ });
+ }
+
+ @Override
+ public void onMapReady(@NonNull NaverMap naverMap) {
+ this.naverMap = naverMap;
+
+ // 초기 좌표를 보이지 않는 위치로 설정 (예: 바다 위의 좌표)
+ CameraUpdate initialUpdate = CameraUpdate.scrollTo(new LatLng(0, 0));
+ naverMap.moveCamera(initialUpdate);
+
+ // 위치 정보 가져오기
+ naverMap.setLocationSource(locationSource);
+
+ // +- 줌컨트롤 버튼 비활성화
+ naverMap.getUiSettings().setZoomControlEnabled(false);
+
+ // 오버레이 위치 아이콘 비활성화
+ LocationOverlay locationOverlay = naverMap.getLocationOverlay();
+ locationOverlay.setVisible(false);
+
+ // 지도 이동 이벤트 설정
+ naverMap.addOnCameraChangeListener((reason, animated) -> {
+ if (reason == REASON_GESTURE) {
+ isCameraMovedByUser = true; // 사용자가 화면을 이동했을 때 플래그 설정
+ isMarkerClicked = false; // 사용자가 화면을 이동하면 마커 클릭 상태 해제
+ if (focusMode) {
+ resetMarkerFocusMode();
+ }
+ FrameLayout mapContainer = requireActivity().findViewById(R.id.fragment_map);
+ View balloonView = mapContainer.findViewById(R.id.dialog_text_message); // ID로 찾기
+ if (balloonView != null) {
+ mapContainer.removeView(balloonView); // 말풍선 제거
+ }
+ View bannerView = mapContainer.findViewById(R.id.fragment_status_banner); // ID로 찾기
+ if (bannerView != null) {
+ mapContainer.removeView(bannerView); // 말풍선 제거
+ }
+ View profileButton = mapContainer.findViewById(R.id.dialog_show_profile); // ID로 찾기
+ if (profileButton != null) {
+ mapContainer.removeView(profileButton); // 말풍선 제거
+ }
+
+ }
+ });
+
+ // 위치 요청 수락 시 트래킹모드 가동, 거부 시 다시 묻기
+ if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ naverMap.setLocationTrackingMode(LocationTrackingMode.Follow);// 트래킹 모드 설정 후에도 오버레이 비활성화
+ naverMap.addOnLocationChangeListener(location -> {
+ locationOverlay.setVisible(false); // 계속해서 오버레이를 비활성화
+ });
+ } else {
+ requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);
+ }
+
+ // Marker 초기화
+ initializeLocationMarker();
+
+ // 지도 클릭 이벤트 설정 (말풍선 닫기)
+ naverMap.setOnMapClickListener((point, coord) -> {
+ if (focusMode) {
+ resetMarkerFocusMode();
+ }
+ resetMarkerFocusMode();
+ FrameLayout mapContainer = requireActivity().findViewById(R.id.fragment_map);
+ View balloonView = mapContainer.findViewById(R.id.dialog_text_message); // ID로 찾기
+ if (balloonView != null) {
+ mapContainer.removeView(balloonView); // 말풍선 제거
+ }
+ View bannerView = mapContainer.findViewById(R.id.fragment_status_banner); // ID로 찾기
+ if (bannerView != null) {
+ mapContainer.removeView(bannerView); // 말풍선 제거
+ }
+ View profileButton = mapContainer.findViewById(R.id.dialog_show_profile); // ID로 찾기
+ if (profileButton != null) {
+ mapContainer.removeView(profileButton); // 말풍선 제거
+ }
+ isMarkerClicked = false; // 마커 클릭 상태 해제
+ });
+
+
+ // 위치 변화 업데이트
+ naverMap.addOnLocationChangeListener(location -> {
+ LatLng currentLocation = new LatLng(location.getLatitude(), location.getLongitude());
+ locationMarker.setPosition(currentLocation);
+
+ // 마커 클릭 상태 또는 초기 화면에서 카메라 이동
+ if (isMarkerClicked) {
+ CameraUpdate update = CameraUpdate.scrollTo(currentLocation)
+ .animate(CameraAnimation.Easing); // 줌 레벨 17.0
+ naverMap.moveCamera(update);
+ } else if (!isCameraMovedByUser) {
+ CameraUpdate update = CameraUpdate.scrollAndZoomTo(currentLocation, 17.0)
+ .animate(CameraAnimation.Easing);
+ naverMap.moveCamera(update);
+ }
+
+
+ View view = getView();
+ tvBuildingName = view.findViewById(R.id.tvBuildingName);
+
+ for (PlaceInfo place : Constants.PLACES) {
+ float[] results = new float[1];
+ Location.distanceBetween(
+ location.getLatitude(), location.getLongitude(),
+ place.getLocation().latitude, place.getLocation().longitude,
+ results
+ );
+
+ if (results[0] <= place.getRadius()) {
+ String buildingName = place.getName();
+ tvBuildingName.setText(buildingName + "에 있어요.");
+ if (!focusMode) {
+ tvBuildingName.setVisibility(View.VISIBLE);
+ }
+ return; // 반경 내 첫 번째 장소를 찾으면 종료
+ }
+ }
+ tvBuildingName.setVisibility(View.GONE); // 반경 내 장소가 없을 경우
+ });
+ }
+
+ // Marker 초기화 메서드
+ private void initializeLocationMarker() {
+ // Marker 객체 생성
+ locationMarker = new Marker();
+ LatLng defaultPosition = new LatLng(0, 0); // 최초 좌표
+ locationMarker.setPosition(defaultPosition);
+ locationMarker.setIcon(OverlayImage.fromResource(R.drawable.img_marker_blue)); // 마커 이미지 설정
+ locationMarker.setWidth(120); // 마커 크기 조정
+ locationMarker.setHeight(140);
+ locationMarker.setMap(naverMap); // 지도에 마커 추가
+
+ // 클릭 이벤트 설정
+ locationMarker.setOnClickListener(overlay -> {
+ if (naverMap == null || getView() == null) {
+ // 지도 초기화가 완료되지 않은 경우
+ Toast.makeText(requireContext(), "지도가 아직 초기화되지 않았습니다.", Toast.LENGTH_SHORT).show();
+ return true; // 이벤트 소비
+ }
+
+ //다른 버튼 안 보이게
+ showMarkerFocusMode();
+
+ // 현재 위치 가져오기
+ LocationOverlay locationOverlay = naverMap.getLocationOverlay();
+ LatLng currentLocation = locationOverlay.getPosition(); // 현재 위치 좌표 가져오기
+ CameraUpdate update = CameraUpdate.scrollAndZoomTo(currentLocation, 20.0)
+ .animate(CameraAnimation.Easing);// 줌 레벨 17.0
+ naverMap.moveCamera(update);
+ isMarkerClicked = true;
+
+ FrameLayout mapContainer = requireActivity().findViewById(R.id.fragment_map);
+
+ // 말풍선 View 인플레이트
+ View balloonView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_text_message, mapContainer, false);
+ //balloonView.setId(R.id.dialog_text_message); // ID 설정
+ mapContainer.addView(balloonView); // 말풍선 추가
+
+ // 배너 View 인플레이트
+ View bannerView = LayoutInflater.from(requireContext()).inflate(R.layout.fragment_status_banner, mapContainer, false);
+ //bannerView.setId(R.id.fragment_status_banner);
+ mapContainer.addView(bannerView);
+
+ // 프로필버튼 View 인플레이트
+ View profileButton = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_show_profile, mapContainer, false);
+ //profileButton.setId(R.id.dialog_show_profile);
+ mapContainer.addView(profileButton);
+ // 클릭 이벤트 설정
+ // 프로필 보기 버튼 클릭 이벤트
+ profileButton.findViewById(R.id.showProfileButton).setOnClickListener(v -> {
+ // BottomSheetDialogFragment 호출
+ EmptyBottomSheetProfile bottomSheet = new EmptyBottomSheetProfile();
+ bottomSheet.show(getParentFragmentManager(), "ProfileBottomSheet");
+ });
+
+ return true; // 클릭 이벤트 소비
+ });
+
+ }
+
+ private void showMarkerFocusMode() {
+ focusMode = true;
+ // 버튼 숨기기
+ notificationButton.setVisibility(View.GONE);
+ promiseListButton.setVisibility(View.GONE);
+ signupNextButton.setVisibility(View.GONE);
+ createPromiseButton.setVisibility(View.GONE);
+ myPageButton.setVisibility(View.GONE);
+ myLocationButton.setVisibility(View.GONE);
+ tvBuildingName.setVisibility(View.GONE);
+ }
+
+
+ private void resetMarkerFocusMode() {
+ focusMode = false;
+ // 버튼 다시 표시
+ notificationButton.setVisibility(View.VISIBLE);
+ promiseListButton.setVisibility(View.VISIBLE);
+ signupNextButton.setVisibility(View.VISIBLE);
+ createPromiseButton.setVisibility(View.VISIBLE);
+ myPageButton.setVisibility(View.VISIBLE);
+ myLocationButton.setVisibility(View.VISIBLE);
+ tvBuildingName.setVisibility(View.VISIBLE);
+ }
+}
diff --git a/app/src/main/java/com/example/mohassu/MapViewActivity.java b/app/src/main/java/com/example/mohassu/MapViewActivity.java
index d35bd92..05262eb 100644
--- a/app/src/main/java/com/example/mohassu/MapViewActivity.java
+++ b/app/src/main/java/com/example/mohassu/MapViewActivity.java
@@ -1,18 +1,24 @@
package com.example.mohassu;
+import com.example.mohassu.Constants;
+
import android.content.pm.PackageManager;
import android.Manifest;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.os.Bundle;
+import android.view.View;
import android.widget.ImageButton;
+import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
+import com.google.android.gms.location.GeofencingClient;
+import com.google.android.gms.location.LocationServices;
import com.naver.maps.geometry.LatLng;
import com.naver.maps.map.CameraUpdate;
import com.naver.maps.map.LocationTrackingMode;
@@ -29,6 +35,8 @@ public class MapViewActivity extends AppCompatActivity implements OnMapReadyCall
private FusedLocationSource locationSource;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1000;
+ private GeofencingClient geofencingClient;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -41,6 +49,8 @@ protected void onCreate(Bundle savedInstanceState) {
// Initialize LocationSource
locationSource = new FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE);
+
+ geofencingClient = LocationServices.getGeofencingClient(this);
}
@Override
@@ -104,9 +114,26 @@ public void onLocationChange(@NonNull Location location) {
LatLng currentLocation = new LatLng(location.getLatitude(), location.getLongitude());
locationOverlay.setPosition(currentLocation); // Update the position to the current location
locationOverlay.setBearing(0); // Reapply the fixed bearing
- });
+ //Geofencing
+ // Check if user is within the geofence
+ for (PlaceInfo place : Constants.PLACES) {
+ float[] results = new float[1];
+ android.location.Location.distanceBetween(
+ location.getLatitude(), location.getLongitude(),
+ place.getLocation().latitude, place.getLocation().longitude,
+ results
+ );
+
+ if (results[0] <= place.getRadius()) {
+ showBuildingName(place.getName());
+ return; // 반경 내 첫 번째 장소를 찾으면 종료
+ }
+ }
+ hideBuildingName(); // 반경 내 장소가 없을 경우
+ });
+
// Custom button to center on current location
ImageButton myLocationButton = findViewById(R.id.btnNowLocation);
myLocationButton.setOnClickListener(v -> {
@@ -133,6 +160,18 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
}
}
+ private void showBuildingName(String buildingName) {
+ TextView tvBuildingName = findViewById(R.id.tvBuildingName);
+ tvBuildingName.setText(buildingName + "에 있어요.");
+ tvBuildingName.setVisibility(View.VISIBLE);
+ }
+
+ private void hideBuildingName() {
+ TextView tvBuildingName = findViewById(R.id.tvBuildingName);
+ tvBuildingName.setVisibility(View.GONE);
+ }
+
+
@Override
protected void onStart() {
super.onStart();
diff --git a/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageHomeFragment.java b/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageHomeFragment.java
index 3841b7a..52e6200 100644
--- a/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageHomeFragment.java
+++ b/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageHomeFragment.java
@@ -1,17 +1,29 @@
package com.example.mohassu.MyPageFragment;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.FrameLayout;
import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
+import com.bumptech.glide.Glide;
import com.example.mohassu.R;
+import com.google.firebase.Firebase;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.firestore.DocumentSnapshot;
+import com.google.firebase.firestore.FirebaseFirestore;
public class MyPageHomeFragment extends Fragment {
@Override
@@ -23,6 +35,62 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ FirebaseAuth auth = FirebaseAuth.getInstance();
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ FirebaseUser currentUser = auth.getCurrentUser();
+
+ if (currentUser != null) {
+ String uid = currentUser.getUid();
+
+ db.collection("users").document(uid)
+ .get()
+ .addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ DocumentSnapshot document = task.getResult();
+ if (document.exists()) {
+ // Firestore에서 사용자 데이터 가져오기
+ String nickName = document.getString("nickname");
+ String name = document.getString("name");
+ String email = document.getString("email");
+ String birthDate = document.getString("birthDate");
+ String photoUrl = document.getString("photoUrl");
+
+ Log.d("Firestore", "Name: " + name + ", Email: " + email + ", nickName" + nickName +", birthDate" + birthDate);
+
+ // UI 업데이트
+ TextView greetingTextView = view.findViewById(R.id.greetingText);
+ TextView userIdView = view.findViewById(R.id.userId);
+ TextView userNickNameView = view.findViewById(R.id.usernickName);
+ TextView userNameView = view.findViewById(R.id.userName);
+ TextView userBirthView = view.findViewById(R.id.userBirth);
+ ImageView profileImageView = view.findViewById(R.id.profileImage);
+
+ if (photoUrl != null && !photoUrl.isEmpty()) {
+ Glide.with(this)
+ .load(photoUrl)
+ .placeholder(R.drawable.img_logo) // 로딩 중 대체 이미지
+ .error(R.drawable.img_logo) // 로딩 실패 시 대체 이미지
+ .into(profileImageView);
+ } else {
+ profileImageView.setImageResource(R.drawable.img_logo); // 기본 이미지
+ }
+
+ greetingTextView.setText(nickName +"님 반갑습니다!");
+ userIdView.setText(email);
+ userNickNameView.setText(nickName);
+ userNameView.setText(name);
+ userBirthView.setText(birthDate);
+ } else {
+ Log.d("Firestore", "No such document!");
+ }
+ } else {
+ Log.w("Firestore", "Error getting document.", task.getException());
+ }
+ });
+ } else {
+ Log.d("FirebaseAuth", "No user is logged in");
+ }
+
// NavController 초기화
NavController navController = Navigation.findNavController(view);
@@ -30,6 +98,12 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
navController.navigateUp();
});
+ TextView logoutText = view.findViewById(R.id.logoutText);
+ logoutText.setOnClickListener(v -> {
+ auth.signOut(); // Firebase 인증 로그아웃
+// navController.navigate(R.id.actionLogout); // 로그인 화면으로 이동
+ });
+
// 다음 프레그먼트를 클릭 시 다음 Fragment로 이동
ImageButton profileEditButton = view.findViewById(R.id.btnProfileEdit);
profileEditButton.setFocusable(false);
@@ -51,4 +125,5 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
navController.navigate(R.id.actionSettingNotification);
});
}
+
}
diff --git a/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableEditFragment.java b/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableEditFragment.java
index 88f8ae3..78751bb 100644
--- a/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableEditFragment.java
+++ b/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableEditFragment.java
@@ -3,6 +3,7 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -14,19 +15,25 @@
import androidx.navigation.Navigation;
import com.example.mohassu.DialogFragment.ClassAddDialogFragment;
+import com.example.mohassu.DialogFragment.ClassEditOrDeleteDialogFragment;
import com.example.mohassu.R;
import com.github.tlaabs.timetableview.Schedule;
import com.github.tlaabs.timetableview.Time;
import com.github.tlaabs.timetableview.TimetableView;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.DocumentSnapshot;
+import com.google.firebase.firestore.FirebaseFirestore;
import java.util.ArrayList;
+import java.util.HashMap;
public class MyPageMyTimeTableEditFragment extends Fragment {
- private static final String PREFS_NAME = "TimetablePrefs"; //파이어베이스상 이메일을 넣어주면 될 듯
- private static final String TIMETABLE_KEY = "timetable";
+ private static final String PREFS_NAME = "TimetablePrefs"; // 로컬 SharedPreferences에 저장
+ private static final String TIMETABLE_KEY = "timetable"; // 로컬 SharedPreferences 키
private TimetableView timetable;
+ private FirebaseFirestore db;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -37,7 +44,9 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- timetable=view.findViewById(R.id.timetable);
+ db = FirebaseFirestore.getInstance();
+
+ timetable = view.findViewById(R.id.timetable);
loadTimetable();
// NavController 초기화
@@ -52,62 +61,120 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
view.findViewById(R.id.btnAddClass).setOnClickListener(v -> {
ClassAddDialogFragment classAddDialogFragment = new ClassAddDialogFragment();
classAddDialogFragment.setOnClassAddedListener((className, classPlace, day, startHour, startMinute, endHour, endMinute) -> {
- // Validate inputs
if (className.isEmpty() || classPlace.isEmpty() || startHour > endHour || (startHour == endHour && startMinute >= endMinute)) {
- if (className.isEmpty() || classPlace.isEmpty()) {
- Toast.makeText(requireContext(), "전부 입력해주세요!", Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(requireContext(), "시작 시간이 종료 시간보다 빠르거나 같아야 합니다.", Toast.LENGTH_SHORT).show();
- }
+ Toast.makeText(requireContext(), "올바른 수업 정보를 입력해주세요.", Toast.LENGTH_SHORT).show();
} else {
addScheduleToTimetable(className, classPlace, day, startHour, startMinute, endHour, endMinute);
- saveTimetable();
}
});
classAddDialogFragment.show(requireActivity().getSupportFragmentManager(), "ClassAddDialog");
});
- // 다음 프레그먼트를 클릭 시 다음 Fragment로 이동
+ timetable.setOnStickerSelectEventListener((idx, schedules) -> {
+ ClassEditOrDeleteDialogFragment classEditOrDeleteDialogFragment = ClassEditOrDeleteDialogFragment.newInstance(schedules.get(0));
+ classEditOrDeleteDialogFragment.setOnClassEditOrDeleteListener(new ClassEditOrDeleteDialogFragment.OnClassEditOrDeleteListener() {
+ @Override
+ public void onEdit(Schedule editedSchedule) {
+ ArrayList updatedSchedules = new ArrayList<>();
+ updatedSchedules.add(editedSchedule);
+ timetable.edit(idx, updatedSchedules);
+ Toast.makeText(requireContext(), "수업 정보가 수정되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onDelete() {
+ timetable.remove(idx);
+ Toast.makeText(requireContext(), "수업 정보가 삭제되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+ });
+ classEditOrDeleteDialogFragment.show(requireActivity().getSupportFragmentManager(), "ClassEditDialog");
+ });
+
Button timeTableSaveButton = view.findViewById(R.id.btnSave);
- timeTableSaveButton.setFocusable(false);
timeTableSaveButton.setOnClickListener(v -> {
+ saveTimetable();
+ saveTimetableToFirestore();
navController.navigate(R.id.actionSaveMyClass);
+
});
}
private void loadTimetable() {
SharedPreferences prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
String json = prefs.getString(TIMETABLE_KEY, null);
-
if (json != null) {
timetable.load(json);
- //Toast.makeText(requireContext(), "저장된 시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
}
}
private void saveTimetable() {
SharedPreferences prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
-
String json = timetable.createSaveData();
editor.putString(TIMETABLE_KEY, json);
editor.apply();
+ Toast.makeText(requireContext(), "로컬에 시간표가 저장되었습니다.", Toast.LENGTH_SHORT).show();
+ }
+
+ private void saveTimetableToFirestore() {
+ String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
+ String json = timetable.createSaveData();
+
+ // 1️Firestore의 timeTableData 필드 업데이트
+ db.collection("users").document(userId)
+ .update("timetableData", json)
+ .addOnSuccessListener(aVoid -> Log.d("Firestore", "timeTableData 필드 업데이트 성공"))
+ .addOnFailureListener(e -> Log.e("Firestore", "timeTableData 업데이트 실패: " + e.getMessage()));
+
+ // 2️Firestore의 timeTable 컬렉션 데이터 삭제 후 새로 추가
+ db.collection("users")
+ .document(userId)
+ .collection("timetable")
+ .get()
+ .addOnSuccessListener(querySnapshot -> {
+ for (DocumentSnapshot document : querySnapshot.getDocuments()) {
+ document.getReference().delete()
+ .addOnSuccessListener(aVoid -> Log.d("Firestore", "기존 timeTable 문서 삭제 성공"))
+ .addOnFailureListener(e -> Log.e("Firestore", "기존 timeTable 문서 삭제 실패: " + e.getMessage()));
+ }
- Toast.makeText(requireContext(), "시간표가 저장되었습니다.", Toast.LENGTH_SHORT).show();
+ ArrayList schedules = timetable.getAllSchedulesInStickers();
+ for (int i = 0; i < schedules.size(); i++) {
+ Schedule schedule = schedules.get(i);
+ HashMap scheduleMap = new HashMap<>();
+ scheduleMap.put("classTitle", schedule.getClassTitle());
+ scheduleMap.put("classPlace", schedule.getClassPlace());
+ scheduleMap.put("professorName", schedule.getProfessorName());
+ scheduleMap.put("day", schedule.getDay());
+ scheduleMap.put("startTime", new HashMap() {{
+ put("hour", schedule.getStartTime().getHour());
+ put("minute", schedule.getStartTime().getMinute());
+ }});
+ scheduleMap.put("endTime", new HashMap() {{
+ put("hour", schedule.getEndTime().getHour());
+ put("minute", schedule.getEndTime().getMinute());
+ }});
+
+ db.collection("users")
+ .document(userId)
+ .collection("timeTable")
+ .add(scheduleMap)
+ .addOnSuccessListener(documentReference -> Log.d("Firestore", "새로운 timeTable 문서 추가 성공"))
+ .addOnFailureListener(e -> Log.e("Firestore", "새로운 timeTable 문서 추가 실패: " + e.getMessage()));
+ }
+ })
+ .addOnFailureListener(e -> Log.e("Firestore", "timeTable 문서 삭제 실패: " + e.getMessage()));
}
private void addScheduleToTimetable(String className, String classPlace, int day, int startHour, int startMinute, int endHour, int endMinute) {
ArrayList schedules = new ArrayList<>();
-
Schedule schedule = new Schedule();
schedule.setClassTitle(className);
schedule.setClassPlace(classPlace);
schedule.setDay(day);
schedule.setStartTime(new Time(startHour, startMinute));
schedule.setEndTime(new Time(endHour, endMinute));
-
schedules.add(schedule);
-
timetable.add(schedules);
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableFragment.java b/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableFragment.java
index e53b0b3..f3e5960 100644
--- a/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableFragment.java
+++ b/app/src/main/java/com/example/mohassu/MyPageFragment/MyPageMyTimeTableFragment.java
@@ -3,6 +3,7 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -15,6 +16,8 @@
import com.example.mohassu.R;
import com.github.tlaabs.timetableview.TimetableView;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.FirebaseFirestore;
public class MyPageMyTimeTableFragment extends Fragment {
@@ -52,12 +55,37 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
}
private void loadTimetable() {
- SharedPreferences prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
- String json = prefs.getString(TIMETABLE_KEY, null);
+// SharedPreferences prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+// String json = prefs.getString(TIMETABLE_KEY, null);
+// timetable.load(json);
+// Toast.makeText(requireContext(), "저장된 시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
- if (json != null) {
- timetable.load(json);
- //Toast.makeText(requireContext(), "저장된 시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
- }
+
+
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ String userId = FirebaseAuth.getInstance().getCurrentUser().getUid(); // 현재 로그인한 사용자 ID 가져오기
+
+ db.collection("users")
+ .document(userId)
+ .get()
+ .addOnSuccessListener(documentSnapshot -> {
+ if (documentSnapshot.exists()) {
+ // timeTableData 필드 가져오기
+ String timeTableData = documentSnapshot.getString("timetableData");
+ if (timeTableData != null) {
+ timetable.load(timeTableData);
+ Toast.makeText(requireContext(), "저장된 시간표를 불러왔습니다.", Toast.LENGTH_SHORT).show();
+ Log.d("Firestore", "TimeTableData: " + timeTableData);
+ // JSON 데이터 처리 로직 추가 가능
+ } else {
+ Log.d("Firestore", "timeTableData 필드가 없습니다.");
+ }
+ } else {
+ Log.d("Firestore", "해당 문서가 존재하지 않습니다.");
+ }
+ })
+ .addOnFailureListener(e -> {
+ Log.e("Firestore", "timeTableData 가져오기 실패: " + e.getMessage());
+ });
}
}
diff --git a/app/src/main/java/com/example/mohassu/PlaceInfo.java b/app/src/main/java/com/example/mohassu/PlaceInfo.java
new file mode 100644
index 0000000..918df36
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/PlaceInfo.java
@@ -0,0 +1,27 @@
+package com.example.mohassu;
+
+import com.naver.maps.geometry.LatLng;
+
+public class PlaceInfo {
+ private String name;
+ private LatLng location;
+ private float radius;
+
+ public PlaceInfo(String name, LatLng location, float radius) {
+ this.name = name;
+ this.location = location;
+ this.radius = radius;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public LatLng getLocation() {
+ return location;
+ }
+
+ public float getRadius() {
+ return radius;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/TestFriendMarkerActivity.java b/app/src/main/java/com/example/mohassu/TestFriendMarkerActivity.java
new file mode 100644
index 0000000..1fc047b
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/TestFriendMarkerActivity.java
@@ -0,0 +1,22 @@
+package com.example.mohassu;
+
+import android.os.Bundle;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.example.mohassu.MainFragment.MainHomeFriendTestFragment;
+
+public class TestFriendMarkerActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_test);
+
+ if (savedInstanceState == null) { // Activity가 처음 실행된 경우
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.main, new MainHomeFriendTestFragment()) // MainHomeFragment로 전환
+ .commit();
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/UserProfileViewModel.java b/app/src/main/java/com/example/mohassu/UserProfileViewModel.java
new file mode 100644
index 0000000..5a2111f
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/UserProfileViewModel.java
@@ -0,0 +1,47 @@
+package com.example.mohassu;
+
+import android.net.Uri;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+public class UserProfileViewModel extends ViewModel {
+ private final MutableLiveData nickname = new MutableLiveData<>();
+ private final MutableLiveData name = new MutableLiveData<>();
+ private final MutableLiveData birthDate = new MutableLiveData<>();
+ private final MutableLiveData photoUri = new MutableLiveData<>();
+
+ public void setNickname(String nickname) {
+ this.nickname.setValue(nickname);
+ }
+
+ public LiveData getNickname() {
+ return nickname;
+ }
+
+ public void setName(String name) {
+ this.name.setValue(name);
+ }
+
+ public LiveData getName() {
+ return name;
+ }
+
+ public void setBirthDate(String birthDate) {
+ this.birthDate.setValue(birthDate);
+ }
+
+ public LiveData getBirthDate() {
+ return birthDate;
+ }
+
+ public void setPhotoUri(Uri uri) {
+ this.photoUri.setValue(uri);
+ }
+
+ public LiveData getPhotoUri() {
+ return photoUri;
+ }
+
+}
diff --git a/app/src/main/java/com/example/mohassu/adapters/FriendAdapter.java b/app/src/main/java/com/example/mohassu/adapters/FriendAdapter.java
new file mode 100644
index 0000000..1641cfc
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/adapters/FriendAdapter.java
@@ -0,0 +1,119 @@
+package com.example.mohassu.adapters;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.example.mohassu.R;
+import com.example.mohassu.models.Friend;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FriendAdapter extends RecyclerView.Adapter {
+ private List friendList; // 전체 친구 목록
+ private List filteredList; // 필터링된 친구 목록
+ private Context context;
+ private OnFriendClickListener onFriendClickListener;
+
+ public FriendAdapter(Context context, List friendList, OnFriendClickListener listener) {
+ this.context = context;
+ this.friendList = new ArrayList<>(friendList);
+ this.filteredList = new ArrayList<>(friendList);
+ this.onFriendClickListener = listener;
+ }
+
+ @NonNull
+ @Override
+ public FriendViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(context).inflate(R.layout.view_friend, parent, false);
+ return new FriendViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull FriendViewHolder holder, int position) {
+ Friend friend = filteredList.get(position);
+ holder.nicknameTextView.setText(friend.getNickname());
+
+ if (friend.getStatusMessage() != null && !friend.getStatusMessage().isEmpty())
+ holder.statusTextView.setText(friend.getStatusMessage());
+ else
+ holder.statusTextView.setText("상태 메시지가 없어요!");
+
+ if(friend.getCurrentClass() != null){
+ holder.placeTextView.setText(friend.getCurrentClass().getClassPlace() + "에서 " +friend.getCurrentClass().getClassTitle() + "수업 중!!!");
+ holder.timeTextView.setText(friend.getCurrentClass().getStartTime().getHour() + "시 " + friend.getCurrentClass().getStartTime().getMinute() +"분 부터 " + friend.getCurrentClass().getEndTime().getHour() + "시 "+friend.getCurrentClass().getEndTime().getMinute() + "분 까지");
+ }
+ else{
+ holder.placeTextView.setText("지금은 수업 중이 아닌디요??");
+ holder.timeTextView.setText("친구 한테 연락해봐요!");
+ }
+ Glide.with(context)
+ .load(friend.getPhotoUrl())
+ .placeholder(R.drawable.img_logo)
+ .error(R.drawable.img_logo)
+ .into(holder.photoImageView);
+
+ holder.itemView.setOnClickListener(v -> {
+ if (onFriendClickListener != null) {
+ onFriendClickListener.onFriendClick(friend);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return filteredList.size();
+ }
+
+ // 검색 기능 추가
+ public void filter(String query) {
+ filteredList.clear();
+ if (query.isEmpty()) {
+ filteredList.addAll(friendList);
+ } else {
+ for (Friend friend : friendList) {
+ if (friend.getNickname().toLowerCase().contains(query.toLowerCase())) {
+ filteredList.add(friend);
+ }
+ }
+ }
+ notifyDataSetChanged();
+ }
+
+ // 🔥 setData() 메서드 추가 (오류 수정)
+ public void setData(List newFriendList) {
+ this.friendList.clear();
+ this.friendList.addAll(newFriendList);
+
+ this.filteredList.clear();
+ this.filteredList.addAll(newFriendList);
+
+ notifyDataSetChanged();
+ }
+
+ public static class FriendViewHolder extends RecyclerView.ViewHolder {
+ TextView nicknameTextView, statusTextView, placeTextView, timeTextView;
+ ImageView photoImageView;
+
+ public FriendViewHolder(@NonNull View itemView) {
+ super(itemView);
+ nicknameTextView = itemView.findViewById(R.id.nickname_text);
+ statusTextView = itemView.findViewById(R.id.state_text);
+ placeTextView = itemView.findViewById(R.id.state_place);
+ timeTextView = itemView.findViewById(R.id.state_time);
+ photoImageView = itemView.findViewById(R.id.profile_image2);
+ }
+ }
+
+ public interface OnFriendClickListener {
+ void onFriendClick(Friend friend);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/models/Friend.java b/app/src/main/java/com/example/mohassu/models/Friend.java
new file mode 100644
index 0000000..9112f16
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/models/Friend.java
@@ -0,0 +1,81 @@
+package com.example.mohassu.models;
+
+import java.io.Serializable;
+
+public class Friend implements Serializable {
+ private String name;
+ private String email;
+ private String photoUrl;
+ private String uid;
+ private String nickname;
+ private String statusMessage;
+ private ScheduleClass currentScheduleClass; // 현재 수업 정보 추가
+
+ public Friend(String uid, String name, String nickname, String email, String statusMessage, String photoUrl, ScheduleClass currentScheduleClass) {
+ this.uid = uid;
+ this.name = name;
+ this.nickname = nickname;
+ this.email = email;
+ this.statusMessage = statusMessage;
+ this.photoUrl = photoUrl;
+ this.currentScheduleClass = currentScheduleClass;
+ }
+
+
+ // Getter & Setter
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPhotoUrl() {
+ return photoUrl;
+ }
+
+ public void setPhotoUrl(String photoUrl) {
+ this.photoUrl = photoUrl;
+ }
+
+ public String getUid() {
+ return uid;
+ }
+
+ public void setUid(String uid) {
+ this.uid = uid;
+ }
+
+ public String getNickname() {
+ return nickname;
+ }
+
+ public void setNickname(String nickname) {
+ this.nickname = nickname;
+ }
+
+ public String getStatusMessage() {
+ return statusMessage;
+ }
+
+ public void setStatusMessage(String statusMessage) {
+ this.statusMessage = statusMessage;
+ }
+
+ public ScheduleClass getCurrentClass() {
+ return currentScheduleClass;
+ }
+
+ public void setCurrentClass(ScheduleClass currentScheduleClass) {
+ this.currentScheduleClass = currentScheduleClass;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/models/ScheduleClass.java b/app/src/main/java/com/example/mohassu/models/ScheduleClass.java
new file mode 100644
index 0000000..9975cc9
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/models/ScheduleClass.java
@@ -0,0 +1,70 @@
+package com.example.mohassu.models;
+
+import java.io.Serializable;
+
+public class ScheduleClass implements Serializable {
+ private String classTitle;
+ private String classPlace;
+ private String professorName;
+ private int day; // 0 = 일요일, 1 = 월요일, ...
+ private Time startTime;
+ private Time endTime;
+
+ public ScheduleClass(String classTitle, String classPlace, String professorName, int day, Time startTime, Time endTime) {
+ this.classTitle = classTitle;
+ this.classPlace = classPlace;
+ this.professorName = professorName;
+ this.day = day;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ }
+
+ // Getter and Setter methods
+ public String getClassTitle() {
+ return classTitle;
+ }
+
+ public void setClassTitle(String classTitle) {
+ this.classTitle = classTitle;
+ }
+
+ public String getClassPlace() {
+ return classPlace;
+ }
+
+ public void setClassPlace(String classPlace) {
+ this.classPlace = classPlace;
+ }
+
+ public String getProfessorName() {
+ return professorName;
+ }
+
+ public void setProfessorName(String professorName) {
+ this.professorName = professorName;
+ }
+
+ public int getDay() {
+ return day;
+ }
+
+ public void setDay(int day) {
+ this.day = day;
+ }
+
+ public Time getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Time startTime) {
+ this.startTime = startTime;
+ }
+
+ public Time getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Time endTime) {
+ this.endTime = endTime;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mohassu/models/Time.java b/app/src/main/java/com/example/mohassu/models/Time.java
new file mode 100644
index 0000000..58f0713
--- /dev/null
+++ b/app/src/main/java/com/example/mohassu/models/Time.java
@@ -0,0 +1,30 @@
+package com.example.mohassu.models;
+
+import java.io.Serializable;
+
+public class Time implements Serializable {
+ private int hour;
+ private int minute;
+
+ public Time(int hour, int minute) {
+ this.hour = hour;
+ this.minute = minute;
+ }
+
+ // Getter and Setter methods
+ public int getHour() {
+ return hour;
+ }
+
+ public void setHour(int hour) {
+ this.hour = hour;
+ }
+
+ public int getMinute() {
+ return minute;
+ }
+
+ public void setMinute(int minute) {
+ this.minute = minute;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/img_default.png b/app/src/main/res/drawable/img_default.png
new file mode 100644
index 0000000..a4ddcc1
Binary files /dev/null and b/app/src/main/res/drawable/img_default.png differ
diff --git a/app/src/main/res/drawable/pic_status_chat.png b/app/src/main/res/drawable/pic_status_chat.png
index 5877d76..768bf81 100644
Binary files a/app/src/main/res/drawable/pic_status_chat.png and b/app/src/main/res/drawable/pic_status_chat.png differ
diff --git a/app/src/main/res/drawable/pic_triangle.xml b/app/src/main/res/drawable/pic_triangle.xml
new file mode 100644
index 0000000..569d1df
--- /dev/null
+++ b/app/src/main/res/drawable/pic_triangle.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/profile_container.png b/app/src/main/res/drawable/profile_container.png
new file mode 100644
index 0000000..7227203
Binary files /dev/null and b/app/src/main/res/drawable/profile_container.png differ
diff --git a/app/src/main/res/layout/activity_map_view.xml b/app/src/main/res/layout/activity_map_view.xml
index 1a20379..43d6b51 100644
--- a/app/src/main/res/layout/activity_map_view.xml
+++ b/app/src/main/res/layout/activity_map_view.xml
@@ -11,6 +11,24 @@
android:layout_height="match_parent"
android:name="com.naver.maps.map.MapFragment" />
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_add_friend.xml b/app/src/main/res/layout/dialog_add_friend.xml
index f5486de..91503da 100644
--- a/app/src/main/res/layout/dialog_add_friend.xml
+++ b/app/src/main/res/layout/dialog_add_friend.xml
@@ -39,7 +39,7 @@
-
+ android:gravity="center_vertical"
+ android:background="@android:color/transparent"
+ >
+ android:textStyle="bold" />
-
-
+ android:text="삭제"
+ android:layout_gravity="top|right"
+ android:textSize="12sp"
+ style="@style/GrayMaterialButtonStyle"
+ />
+
+
+ android:textColor="@color/black"
+ android:padding="8dp" />
+ android:layout_marginBottom="6dp" />
+ android:spinnerMode="dropdown"
+ android:theme="@style/CustomSpinner"
+ android:popupBackground="@color/lightGray"/>
+ android:spinnerMode="dropdown"
+ android:theme="@style/CustomSpinner"
+ android:background="@color/white"
+ android:popupBackground="@color/lightGray"/>
+ android:text="~"
+ android:textColor="@color/black"/>
+ android:spinnerMode="dropdown"
+ android:theme="@style/CustomSpinner"
+ android:popupBackground="@color/lightGray"/>
@@ -128,7 +138,7 @@
android:text="강의 장소"
android:textSize="18sp"
android:textColor="@android:color/black"
- android:layout_marginBottom="4dp" />
+ android:layout_marginBottom="6dp" />
+
+
+
diff --git a/app/src/main/res/layout/dialog_edit_message.xml b/app/src/main/res/layout/dialog_edit_message.xml
new file mode 100644
index 0000000..c5b0b45
--- /dev/null
+++ b/app/src/main/res/layout/dialog_edit_message.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_show_profile.xml b/app/src/main/res/layout/dialog_show_profile.xml
new file mode 100644
index 0000000..d4369bd
--- /dev/null
+++ b/app/src/main/res/layout/dialog_show_profile.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_text_message.xml b/app/src/main/res/layout/dialog_text_message.xml
new file mode 100644
index 0000000..935e1f4
--- /dev/null
+++ b/app/src/main/res/layout/dialog_text_message.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_bottom_sheet_check_profile.xml b/app/src/main/res/layout/fragment_bottom_sheet_check_profile.xml
index 7643ea6..3ba14b4 100644
--- a/app/src/main/res/layout/fragment_bottom_sheet_check_profile.xml
+++ b/app/src/main/res/layout/fragment_bottom_sheet_check_profile.xml
@@ -1,11 +1,11 @@
-
@@ -68,7 +68,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="25dp"
- tool:text="이호근"
+ android:text="#name"
android:textColor="@color/white"
android:layout_marginBottom="20dp"
/>
@@ -87,13 +87,12 @@
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_main_home.xml b/app/src/main/res/layout/fragment_main_home.xml
index c78c3c9..f23cfeb 100644
--- a/app/src/main/res/layout/fragment_main_home.xml
+++ b/app/src/main/res/layout/fragment_main_home.xml
@@ -6,11 +6,26 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ android:layout_height="match_parent" />
+
+
diff --git a/app/src/main/res/layout/fragment_sign_up1.xml b/app/src/main/res/layout/fragment_sign_up1.xml
index cc9dfba..a8cfc3a 100644
--- a/app/src/main/res/layout/fragment_sign_up1.xml
+++ b/app/src/main/res/layout/fragment_sign_up1.xml
@@ -1,113 +1,111 @@
-
-
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ android:contentDescription="뒤로가기 버튼"
+ android:foregroundTint="@color/black"
+ android:src="@drawable/ic_back" />
+ android:textStyle="bold" />
+ android:layout_marginBottom="40dp"
+ android:background="#BDBDBD" />
+ android:gravity="center"
+ android:text="아이디와 비밀번호를 입력해주세요!"
+ android:textColor="@color/black"
+ android:textSize="24sp"
+ android:textStyle="bold" />
+ android:textSize="16sp" />
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ android:textSize="16sp" />
+ android:textSize="16sp" />
-
-
+
-
-
+ android:layout_marginTop="40dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_sign_up2.xml b/app/src/main/res/layout/fragment_sign_up2.xml
index d644c7a..5e565ff 100644
--- a/app/src/main/res/layout/fragment_sign_up2.xml
+++ b/app/src/main/res/layout/fragment_sign_up2.xml
@@ -87,7 +87,8 @@
android:hint="이름"
android:inputType="text"
android:padding="12dp"
- android:textColor="@color/black" />
+ android:textColor="@color/black"
+ android:imeOptions="actionDone"/>
diff --git a/app/src/main/res/layout/fragment_status_banner.xml b/app/src/main/res/layout/fragment_status_banner.xml
new file mode 100644
index 0000000..378d4b2
--- /dev/null
+++ b/app/src/main/res/layout/fragment_status_banner.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/my_marker.xml b/app/src/main/res/layout/my_marker.xml
new file mode 100644
index 0000000..693b2cb
--- /dev/null
+++ b/app/src/main/res/layout/my_marker.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/profile_container_container.xml b/app/src/main/res/layout/profile_container_container.xml
new file mode 100644
index 0000000..c5a313b
--- /dev/null
+++ b/app/src/main/res/layout/profile_container_container.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_friend.xml b/app/src/main/res/layout/view_friend.xml
index 3957227..65e07d7 100644
--- a/app/src/main/res/layout/view_friend.xml
+++ b/app/src/main/res/layout/view_friend.xml
@@ -20,18 +20,30 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
+
+
+ app:layout_constraintTop_toTopOf="parent" />
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_main_graph.xml b/app/src/main/res/navigation/nav_main_graph.xml
index 7b449d0..64873d2 100644
--- a/app/src/main/res/navigation/nav_main_graph.xml
+++ b/app/src/main/res/navigation/nav_main_graph.xml
@@ -44,15 +44,26 @@
tools:layout="@layout/fragment_main_promise_list">
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/navigation/nav_start_login_and_signup_graph.xml b/app/src/main/res/navigation/nav_start_login_and_signup_graph.xml
index 2445b9e..b07c913 100644
--- a/app/src/main/res/navigation/nav_start_login_and_signup_graph.xml
+++ b/app/src/main/res/navigation/nav_start_login_and_signup_graph.xml
@@ -83,6 +83,7 @@
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 374c4cf..583e9c3 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -24,6 +24,12 @@
- @android:color/black
- 14sp
+
+