Newer
Older
NemophilaClient / app / src / main / java / com / example / nemophila / MapsFragment.java
  1. package com.example.nemophila;
  2.  
  3. import androidx.activity.result.ActivityResultLauncher;
  4. import androidx.activity.result.contract.ActivityResultContracts;
  5. import androidx.annotation.NonNull;
  6. import androidx.annotation.Nullable;
  7. import androidx.core.app.ActivityCompat;
  8. import androidx.core.content.ContextCompat;
  9. import androidx.core.content.res.ResourcesCompat;
  10. import androidx.fragment.app.DialogFragment;
  11. import androidx.fragment.app.Fragment;
  12. import androidx.lifecycle.Observer;
  13. import androidx.lifecycle.ViewModelProvider;
  14.  
  15. import android.Manifest;
  16. import android.annotation.SuppressLint;
  17. import android.content.Intent;
  18. import android.content.pm.PackageManager;
  19. import android.graphics.Bitmap;
  20. import android.graphics.BitmapFactory;
  21. import android.graphics.drawable.BitmapDrawable;
  22. import android.graphics.drawable.Drawable;
  23. import android.location.Location;
  24. import android.location.LocationListener;
  25. import android.location.LocationManager;
  26. import android.os.Bundle;
  27. import android.provider.Settings;
  28. import android.util.Log;
  29. import android.view.LayoutInflater;
  30. import android.view.View;
  31. import android.view.ViewGroup;
  32. import android.widget.ImageButton;
  33. import android.widget.TextView;
  34. import android.widget.Toast;
  35.  
  36. import com.example.nemophila.databinding.ActivityMainBinding;
  37. import com.example.nemophila.entities.Post;
  38. import com.example.nemophila.entities.Shop;
  39. import com.example.nemophila.viewmodels.FriendViewModel;
  40. import com.example.nemophila.viewmodels.PostsViewModel;
  41. import com.example.nemophila.viewmodels.ShopsViewModel;
  42. import com.google.android.gms.maps.CameraUpdateFactory;
  43. import com.google.android.gms.maps.GoogleMap;
  44. import com.google.android.gms.maps.OnMapReadyCallback;
  45. import com.google.android.gms.maps.SupportMapFragment;
  46. import com.google.android.gms.maps.model.BitmapDescriptor;
  47. import com.google.android.gms.maps.model.BitmapDescriptorFactory;
  48. import com.google.android.gms.maps.model.CameraPosition;
  49. import com.google.android.gms.maps.model.GroundOverlay;
  50. import com.google.android.gms.maps.model.GroundOverlayOptions;
  51. import com.google.android.gms.maps.model.LatLng;
  52. import com.google.android.gms.maps.model.LatLngBounds;
  53. import com.google.android.gms.maps.model.Marker;
  54. import com.google.android.gms.maps.model.MarkerOptions;
  55. import com.google.common.collect.Maps;
  56.  
  57. import java.util.ArrayList;
  58. import java.util.Map;
  59.  
  60. public class MapsFragment extends Fragment implements LocationListener {
  61. ShopsViewModel shopsViewModel;
  62. FriendViewModel friendViewModel;
  63. PostsViewModel postsViewModel;
  64.  
  65. Nemophila nemophila;
  66. private GoogleMap mMap;
  67. private ActivityMainBinding binding;
  68. private LatLng currentLatlng = null;
  69. private LatLng initialLatlng;
  70. private LatLng shopLatlng;
  71. // private LatLng testLatlng;
  72. // private LatLng testLatlng2;
  73. private LatLng tapLatlng;
  74. // private CameraPosition nowCamera;
  75. // private LatLng nowLatlng;
  76. private Marker currentMarker;
  77. private BitmapDescriptor bd;
  78. private boolean isLongClick;
  79.  
  80.  
  81. LocationManager locationManager;
  82.  
  83. private OnMapReadyCallback callback = new OnMapReadyCallback() {
  84.  
  85. @Override
  86. public void onMapReady(GoogleMap googleMap) {
  87.  
  88. nemophila = (Nemophila) getActivity().getApplication();
  89. mMap = googleMap;
  90.  
  91. //ViewModelへのアクセス
  92. shopsViewModel = new ViewModelProvider(getActivity()).get(ShopsViewModel.class);
  93. friendViewModel = new ViewModelProvider(getActivity()).get(FriendViewModel.class);
  94. postsViewModel = new ViewModelProvider(getActivity()).get(PostsViewModel.class);
  95.  
  96.  
  97. //フレンドの更新が入った時の処理(LiveDataへの購読)
  98. friendViewModel.getFriends(nemophila.getUid());
  99. friendViewModel.getFriendsLiveData().observe(getActivity(), friends -> {
  100. Toast.makeText(getActivity(),
  101. String.format("フレンドの更新を確認しました。"),
  102. Toast.LENGTH_SHORT)
  103. .show();
  104. //nemophilaにセットしておく
  105. nemophila.setFriends(friends);
  106. });
  107.  
  108.  
  109.  
  110. // 店情報の更新が入った時の処理(LiveDataへの購読)
  111. shopsViewModel.getShopsLiveData().observe(getActivity(), shops -> {
  112. Toast.makeText(getActivity(),
  113. String.format("表示していない店を確認しました。ピンを立てます"),
  114. Toast.LENGTH_SHORT)
  115. .show();
  116.  
  117. for (Shop shop : shops) {
  118. //受け取ったshopsにfriendsの投稿が含まれているかを確認,受け取ったshopsに対してMarkerが立っているかを確認
  119.  
  120. //observeの中にobserveはうまくいかなかった
  121. // postsViewModel.loadShopPost(shop.getSid());
  122. // postsViewModel.getShopPostLiveData().observe(getActivity(), new Observer <ArrayList<Post>>() {
  123. // @Override
  124. // public void onChanged(ArrayList<Post> posts) {
  125. // ArrayList<String> ids = postsViewModel.getUserIds();
  126. //
  127. // for(int i = 0; i < ids.size(); i++) {
  128. // ArrayList<String> fids = nemophila.getFriendIds();
  129. // for(int j = 0; j < fids.size(); j++) {
  130. // if( ( ids.get(i).equals(fids.get(j)) || ids.get(i).equals(nemophila.getUid()) ) && shopsViewModel.getMarker(shop) == null ){
  131. // //各shopに対応するMarkerがなければMarkerを立てる
  132. // shopLatlng = new LatLng(shop.getLatitude(), shop.getLongitude());
  133. // System.out.println(shopLatlng);
  134. // Marker createMaker = mMap.addMarker(new MarkerOptions().position(shopLatlng).title(""));
  135. // //マーカーに店情報を持たせる
  136. // createMaker.setTag(shop);
  137. // //ShopToMarkerに紐づけ
  138. // shopsViewModel.setShopAndMarker(shop, createMaker);
  139. // }
  140. // }
  141. // }
  142. // }
  143. // });
  144.  
  145. if ( shopsViewModel.getMarker(shop) == null) { //フレンド以外の投稿のピンも立てたい場合
  146. //if( && shopsViewModel.getMarker(shop) == null) {
  147.  
  148. //各shopに対応するMarkerがなければMarkerを立てる
  149. shopLatlng = new LatLng(shop.getLatitude(), shop.getLongitude());
  150. System.out.println(shopLatlng);
  151. Marker createMaker = mMap.addMarker(new MarkerOptions().position(shopLatlng).title(""));
  152. //マーカーに店情報を持たせる
  153. createMaker.setTag(shop);
  154. //ShopToMarkerに紐づけ
  155. shopsViewModel.setShopAndMarker(shop, createMaker);
  156. }
  157. }
  158. });
  159.  
  160. // 長押しを認識した後の処理(LiveDataへの購読)
  161. shopsViewModel.getNearShopsLiveData().observe(getActivity(), shops -> {
  162. Toast.makeText(getActivity(),
  163. String.format("近辺の店を確認しました。ダイアログを表示します"),
  164. Toast.LENGTH_SHORT)
  165. .show();
  166.  
  167. //長押し時は周辺のピンを全て取得し、ダイアログに表示する
  168. DialogFragment dialogFragment = new MapsDialogFragment(shops);
  169. dialogFragment.show(getActivity().getSupportFragmentManager(),"mapsdialog");
  170. });
  171.  
  172. //初期画面の座標(現在地をロードするまで表示)
  173. //initialLatlng = new LatLng(39,138);
  174. initialLatlng = new LatLng(nemophila.getCameraLatitude(), nemophila.getCameraLongitude());
  175. //初期画面に移動
  176. mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(initialLatlng, nemophila.getZoom()));
  177.  
  178.  
  179. //画面が動いたとき
  180. mMap.setOnCameraIdleListener(() -> {
  181. //カメラの座標とZOOM倍率を保存
  182. //nowCamera = mMap.getCameraPosition();
  183. nemophila.setCameraLatitude(mMap.getCameraPosition().target.latitude);
  184. nemophila.setCameraLongitude(mMap.getCameraPosition().target.longitude);
  185. nemophila.setZoom(mMap.getCameraPosition().zoom);
  186. //Shopの描画範囲を指定
  187. shopsViewModel.setViewArea(nemophila.getCameraLongitude() + 1, nemophila.getCameraLatitude() + 1, nemophila.getCameraLongitude() - 1, nemophila.getCameraLatitude() - 1);
  188. });
  189.  
  190.  
  191. // test用 座標を確認するため
  192. // タップした時のリスナーをセット
  193. mMap.setOnMapClickListener(tapLocation -> {
  194. // map(ピン以外)をtapされた位置の緯度経度
  195. tapLatlng = new LatLng(tapLocation.latitude, tapLocation.longitude);
  196. Toast.makeText(getActivity(),
  197. String.format("%s", tapLatlng),
  198. Toast.LENGTH_SHORT)
  199. .show();
  200. });
  201.  
  202.  
  203. //長押し時に店を作成し、その座標にピンを立てる
  204. //長押し時にその座標を保存し、投稿画面に移り、Shop作成完了時にはピンを立て、Shop画面に移行
  205. mMap.setOnMapLongClickListener(longpushLocation -> {
  206. //長押しされた位置の緯度経度を取得
  207. //LatLng newlocation = new LatLng(longpushLocation.latitude, longpushLocation.longitude);
  208.  
  209. //長押し座標を画面中心にしておく
  210. //zoomMap(longpushLocation.latitude, longpushLocation.longitude);
  211. //Nemophilaに座標を保存
  212. nemophila.setCurrentLatitude(longpushLocation.latitude);
  213. nemophila.setCurrentLongitude(longpushLocation.longitude);
  214. //長押しした場合は今からShopを作成するので、CurrentShopをnullで登録しておく
  215. nemophila.setCurrentShop(null);
  216.  
  217. //長押しでダイアログを表示
  218. //テスト用
  219. //shopsViewModel.longClickViewArea(longpushLocation.longitude+1, longpushLocation.latitude+1, longpushLocation.longitude-1, longpushLocation.latitude-1);
  220. //本番環境は↓の範囲で
  221. shopsViewModel.longClickViewArea(longpushLocation.longitude+0.001, longpushLocation.latitude+0.001, longpushLocation.longitude-0.001, longpushLocation.latitude-0.001);
  222. });
  223.  
  224. // ピンをクリックした場合
  225. mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
  226. @Override
  227. public boolean onMarkerClick(Marker marker) {
  228. //店の詳細と投稿一覧を表示
  229. //ここでshopActivityを呼び出す
  230.  
  231. //下からクリックしたことを通知
  232. //Toast.makeText(getActivity(), "ピンクリック", Toast.LENGTH_SHORT).show();
  233.  
  234. //現在地マーカーをクリックしたときのみ例外
  235. if(marker.getTag() == null) {
  236. //以下の処理をストップ
  237. return false;
  238. }
  239.  
  240. //選んだ店をsetする
  241. nemophila.setCurrentShop((Shop) marker.getTag());
  242. System.out.println(nemophila.getCurrentShop().getName());
  243.  
  244. //ShopActivity画面に遷移
  245. Intent intent = new Intent(getActivity(), ShopActivity.class);
  246. startActivity(intent);
  247.  
  248. return false;
  249. }
  250. });
  251. }
  252. };
  253.  
  254. @Nullable
  255. @Override
  256. public View onCreateView(@NonNull LayoutInflater inflater,
  257. @Nullable ViewGroup container,
  258. @Nullable Bundle savedInstanceState) {
  259.  
  260.  
  261. return inflater.inflate(R.layout.fragment_maps, container, false);
  262. }
  263.  
  264. @Override
  265. public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
  266. super.onViewCreated(view, savedInstanceState);
  267.  
  268. //binding = ActivityMainBinding.inflate(getLayoutInflater());
  269. //getActivity().setContentView(binding.getRoot());
  270.  
  271. if (ActivityCompat.checkSelfPermission(
  272. getContext(),
  273. Manifest.permission.ACCESS_FINE_LOCATION)
  274. != PackageManager.PERMISSION_GRANTED) {
  275.  
  276. requestPermissionLauncher.launch(
  277. Manifest.permission.ACCESS_FINE_LOCATION);
  278. }
  279. else{
  280. locationStart();
  281. }
  282.  
  283. // // Obtain the SupportMapFragment and get notified when the map is ready to be used.
  284. // SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
  285. // .findFragmentById(R.id.map);
  286. // assert mapFragment != null;
  287. // mapFragment.getMapAsync(this);
  288.  
  289. SupportMapFragment mapFragment =
  290. (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
  291. if (mapFragment != null) {
  292. mapFragment.getMapAsync(callback);
  293. }
  294.  
  295. //現在地アイコン用の準備
  296. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_current);
  297. Bitmap afterBitmap = Bitmap.createScaledBitmap(bitmap, 100, 100, true);
  298. bd = BitmapDescriptorFactory.fromBitmap(afterBitmap);
  299. }
  300.  
  301.  
  302. private void zoomMap(double latitude, double longitude) {
  303. // 表示する東西南北の緯度経度を設定
  304. double south = latitude * (1 - 0.00005);
  305. double west = longitude * (1 - 0.00005);
  306. double north = latitude * (1 + 0.00005);
  307. double east = longitude * (1 + 0.00005);
  308.  
  309. LatLng latlng = new LatLng(latitude, longitude);
  310.  
  311. // LatLngBounds (LatLng southwest, LatLng northeast)
  312. //左下、右上
  313. LatLngBounds bounds = LatLngBounds.builder()
  314. .include(new LatLng(south, west))
  315. .include(new LatLng(north, east))
  316. .build();
  317.  
  318. int width = getResources().getDisplayMetrics().widthPixels;
  319. int height = getResources().getDisplayMetrics().heightPixels;
  320.  
  321. // static CameraUpdate.newLatLngBounds(LatLngBounds bounds, int width, int height, int padding)
  322. mMap.moveCamera(CameraUpdateFactory.
  323. newLatLngBounds(bounds, width, height, 0));
  324.  
  325. //ズーム処理
  326. mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, nemophila.getZoom()));
  327. }
  328.  
  329. //現在地の表示
  330. private void setIcon(double latitude, double longitude) {
  331. //現在地をLatLng型で取得
  332. LatLng current_location = new LatLng(latitude, longitude);
  333.  
  334. //初回現在地取得時
  335. if (currentMarker == null) {
  336. currentMarker=mMap.addMarker(new MarkerOptions().position(current_location).title("現在地").icon(bd));
  337. } else {
  338. //2回目移行
  339. currentMarker.setPosition(current_location);
  340. }
  341. }
  342.  
  343.  
  344. private final ActivityResultLauncher<String>
  345. requestPermissionLauncher = registerForActivityResult(
  346. new ActivityResultContracts.RequestPermission(),
  347. isGranted -> {
  348. if (isGranted) {
  349. locationStart();
  350. }
  351. else {
  352. Toast toast = Toast.makeText(getActivity(),
  353. "これ以上なにもできません", Toast.LENGTH_SHORT);
  354. toast.show();
  355. }
  356. });
  357.  
  358. //現在地の取得
  359. @SuppressLint("MissingPermission")
  360. private void locationStart(){
  361. Log.d("debug","locationStart()");
  362.  
  363. // LocationManager インスタンス生成
  364. locationManager =
  365. (LocationManager) getContext().getSystemService(getContext().LOCATION_SERVICE);
  366.  
  367. if (locationManager != null && locationManager.isProviderEnabled(
  368. LocationManager.GPS_PROVIDER)) {
  369.  
  370. Log.d("debug", "location manager Enabled");
  371. } else {
  372. // GPSを設定するように促す
  373. Intent settingsIntent =
  374. new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
  375. startActivity(settingsIntent);
  376. Log.d("debug", "not gpsEnable, startActivity");
  377. }
  378.  
  379. if (ContextCompat.checkSelfPermission(getContext(),
  380. Manifest.permission.ACCESS_FINE_LOCATION) !=
  381. PackageManager.PERMISSION_GRANTED) {
  382. ActivityCompat.requestPermissions(getActivity(),
  383. new String[]{Manifest.permission.ACCESS_FINE_LOCATION,}, 1000);
  384.  
  385. Log.d("debug", "checkSelfPermission false");
  386. return;
  387. }
  388.  
  389. locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
  390. 1000, 50, this);
  391.  
  392. }
  393.  
  394. @Override
  395. public void onLocationChanged(Location location) {
  396. //初期画面は現在地を中心にするため...
  397. if (currentLatlng == null){
  398. //↓現在地ロード後画面中心を現在地にする場合
  399. //zoomMap(location.getLatitude(), location.getLongitude());
  400. //ロード画面の終了
  401. //getView().findViewById(R.id.LL_Load).setVisibility(View.GONE);
  402.  
  403. //現在地ボタンを表示
  404. getView().findViewById(R.id.currentButton).setVisibility(View.VISIBLE);
  405. ImageButton button1 = getView().findViewById(R.id.currentButton);
  406.  
  407. button1.setOnClickListener( v -> {
  408. Log.d("debug", "currentbutton, 現在地にカメラを移動");
  409. System.out.println(shopsViewModel.getShopsLiveData().getValue());
  410. //現在地にカメラを移動
  411. zoomMap(currentLatlng.latitude, currentLatlng.longitude);
  412. });
  413. }
  414.  
  415. //現在地が変更されるたびに現在地アイコンを移動
  416. //LatLng型で受け取っておく
  417. currentLatlng = new LatLng(location.getLatitude(), location.getLongitude());
  418.  
  419. //現在地アイコンを表示.このsetIcon内にzoomMap処理もあるので注意
  420. setIcon(location.getLatitude(),location.getLongitude());
  421. }
  422.  
  423. @Override
  424. public void onProviderEnabled(String provider) {
  425.  
  426. }
  427.  
  428. @Override
  429. public void onProviderDisabled(String provider) {
  430.  
  431. }
  432.  
  433. }