diff --git a/assets/images/green_map_pin.png b/assets/images/green_map_pin.png new file mode 100644 index 00000000..3cd907d3 Binary files /dev/null and b/assets/images/green_map_pin.png differ diff --git a/lib/controllers/my_place_controller.dart b/lib/controllers/my_place_controller.dart index ddd8aaef..360132ba 100644 --- a/lib/controllers/my_place_controller.dart +++ b/lib/controllers/my_place_controller.dart @@ -30,8 +30,9 @@ class MyPlaceController extends GetxController { RxList markers = [].obs; RxBool isLoading = true.obs; - final RxDouble selectedLatitude = 37.503640.obs; - final RxDouble selectedLongitude = 127.044829.obs; + final RxDouble selectedLatitude = 37.566422.obs; + final RxDouble selectedLongitude = 126.977948.obs; + RxBool isCameraTrackingUser = true.obs; final RxString myPlaceName = "HOME".obs; final RxInt selectedPlace = 0.obs; @@ -49,25 +50,13 @@ class MyPlaceController extends GetxController { bottomSheetController.minimize(); } - void updateMarker(LatLng latLng) { - markers.clear(); - markers.add( - Marker( - markerId: MarkerId('clicked_position'), - position: latLng, - infoWindow: InfoWindow( - title: 'Clicked Position', - snippet: 'Lat: ${latLng.latitude}, Lng: ${latLng.longitude}', - ), - ), - ); + void updateCoordinate(LatLng latLng) { selectedLatitude.value = latLng.latitude; selectedLongitude.value = latLng.longitude; } Future initCurrentLocation() async { try { - await LocationService().initCurrentLocation(); currentCameraPosition = CameraPosition( target: LatLng( _locationService.currentLocation!.latitude!, @@ -123,4 +112,19 @@ class MyPlaceController extends GetxController { getSelectedPlace() { return selectedPlace.value; } + + setCameraOnCurrentLocation() { + isCameraTrackingUser = true.obs; + + currentCameraPosition = CameraPosition( + target: LatLng( + _locationService.currentLocation!.latitude!, + _locationService.currentLocation!.longitude!, + ), + zoom: 16.0, + ); + googleMapController?.animateCamera( + CameraUpdate.newCameraPosition(currentCameraPosition), + ); + } } diff --git a/lib/main.dart b/lib/main.dart index fcf9a77e..dbc40135 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -32,15 +32,15 @@ Future main() async { ]); await dotenv.load(fileName: ".env"); await GetStorage.init(); - final MainController mainController = MainController(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); - mainController.checkVersion(); KakaoSdk.init(nativeAppKey: dotenv.env['NATIVE_APP_KEY']!); LocationService().initBackgroundLocation(); String initialRoute = await AuthService().isLogin() ? '/main' : '/permission'; + final MainController mainController = Get.put(MainController(), permanent: true); + mainController.checkVersion(); runApp( MyApp( initialRoute: initialRoute, diff --git a/lib/screens/map_screen.dart b/lib/screens/map_screen.dart index ce7923be..24716d8e 100644 --- a/lib/screens/map_screen.dart +++ b/lib/screens/map_screen.dart @@ -56,6 +56,7 @@ class MapScreen extends StatelessWidget { mapController.googleMapController = ctrl; }, myLocationEnabled: true, + myLocationButtonEnabled: false, style: mapController.mapStyle, polygons: Set.of(mapController.pixels), ), @@ -98,7 +99,7 @@ class MapScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ PixelCountInfo(count: 128), - CurrentLocationButton(), + CurrentLocationButton(checkController: "map",), ], ), ), diff --git a/lib/screens/my_place_screen.dart b/lib/screens/my_place_screen.dart index ff8b5cbb..4a66f410 100644 --- a/lib/screens/my_place_screen.dart +++ b/lib/screens/my_place_screen.dart @@ -5,6 +5,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import '../constants/app_colors.dart'; import '../controllers/my_place_controller.dart'; import '../service/location_service.dart'; +import '../widgets/map/current_location_button.dart'; class MyPlaceScreen extends StatelessWidget { MyPlaceScreen({super.key}); @@ -12,26 +13,37 @@ class MyPlaceScreen extends StatelessWidget { @override Widget build(BuildContext context) { final MyPlaceController myPlaceController = Get.put(MyPlaceController()); + const double mapPinHeight = 60; + const double mapPinWidth = mapPinHeight * 0.85; - return Scaffold( - appBar: AppBar( - leading: IconButton( - onPressed: () { - Get.back(); - }, - icon: Icon( - Icons.arrow_back_ios, - color: AppColors.buttonColor, - ), + final PreferredSizeWidget appBar = AppBar( + leading: IconButton( + onPressed: () { + Get.back(); + }, + icon: Icon( + Icons.arrow_back_ios, + color: AppColors.buttonColor, ), - backgroundColor: AppColors.background, - title: Text( - '내 장소 등록', - style: TextStyle( - color: AppColors.textPrimary, - ), + ), + backgroundColor: AppColors.background, + title: Text( + '내 장소 등록', + style: TextStyle( + color: AppColors.textPrimary, ), ), + ); + final Widget mapPinImage = Image.asset( + 'assets/images/green_map_pin.png', + height: mapPinHeight, + width: mapPinWidth, + ); + + final double appBarHeight = appBar.preferredSize.height; + + return Scaffold( + appBar: appBar, body: Obx(() { if (myPlaceController.isLoading.value) { return const Center( @@ -58,36 +70,80 @@ class MyPlaceScreen extends StatelessWidget { myPlaceController.googleMapController = ctrl; }, myLocationEnabled: false, + zoomControlsEnabled: false, style: myPlaceController.mapStyle, markers: Set.of(myPlaceController.markers), - onTap: (LatLng latLng) { - myPlaceController.updateMarker(latLng); + onCameraIdle: () async { + final GoogleMapController? controller = + myPlaceController.googleMapController; + LatLng center = LatLng( + LocationService().currentLocation!.latitude!, + LocationService().currentLocation!.longitude!, + ); + if (controller != null) { + LatLngBounds visibleRegion = + await controller.getVisibleRegion(); + center = LatLng( + (visibleRegion.northeast.latitude + + visibleRegion.southwest.latitude) / + 2, + (visibleRegion.northeast.longitude + + visibleRegion.southwest.longitude) / + 2, + ); + } + myPlaceController.updateCoordinate(center); }, ); }, ), Positioned( - top: 20, - right: 10, - child: GestureDetector( - onTap: () { - myPlaceController.openMyPlaceBottomSheet(); - }, - child: Container( - padding: EdgeInsets.symmetric(vertical: 7, horizontal: 20), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: AppColors.primary, + top: (MediaQuery.of(context).size.height - appBarHeight) / 2 - + (mapPinHeight - 2), + left: + (MediaQuery.of(context).size.width / 2) - (mapPinWidth / 2), + child: mapPinImage, + ), + Positioned( + bottom: 15, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.only(right: 10.0), + child: CurrentLocationButton( + checkController: "myPlace", + ), ), - child: Text( - '등록', - style: TextStyle( - color: AppColors.textPrimary, - fontSize: 15, - fontWeight: FontWeight.w700, + Padding( + padding: const EdgeInsets.all(10), + child: GestureDetector( + onTap: () { + myPlaceController.openMyPlaceBottomSheet(); + }, + child: Container( + width: MediaQuery.of(context).size.width - 20, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: AppColors.primary, + ), + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: Text( + '등록', + style: TextStyle( + color: AppColors.textBlack, + fontSize: 20, + fontWeight: FontWeight.w700, + ), + ), + ), + ), + ), ), ), - ), + ], ), ), ], diff --git a/lib/utils/dio_service.dart b/lib/utils/dio_service.dart index 3f2881ca..44cbfad4 100644 --- a/lib/utils/dio_service.dart +++ b/lib/utils/dio_service.dart @@ -42,9 +42,9 @@ class DioService { return handler.next(response); }, onError: ( - DioException dioException, - ErrorInterceptorHandler errorInterceptorHandler, - ) async { + DioException dioException, + ErrorInterceptorHandler errorInterceptorHandler, + ) async { if (dioException.response?.statusCode == HttpStatus.unauthorized) { try { ReissueResponse reissueResponse = await reissueToken(); @@ -52,7 +52,7 @@ class DioService { userManager.setRefreshToken(reissueResponse.refreshToken!); Response resendResponse = - await resendRequest(dioException, reissueResponse); + await resendRequest(dioException, reissueResponse); errorInterceptorHandler.resolve(resendResponse); debugPrint('-------------refresh---------------'); } catch (err) { @@ -69,9 +69,9 @@ class DioService { } Future> resendRequest( - DioException dioException, - ReissueResponse reissueResponse, - ) async { + DioException dioException, + ReissueResponse reissueResponse, + ) async { final options = dioException.requestOptions; final dio = Dio(); options.headers.addAll({ @@ -87,7 +87,7 @@ class DioService { var response = await dio .post("$baseUrl/auth/reissue", data: {"refreshToken": refreshToken}); ReissueResponse reissueResponse = - ReissueResponse.fromJson(response.data["data"]); + ReissueResponse.fromJson(response.data["data"]); UserManager().setTokenReissued(); return reissueResponse; } @@ -102,11 +102,11 @@ class DioService { options.extra['requestTimestamp'] = requestTimestamp; debugPrint( '---------------[Request - $requestTimestamp]---------------\n' - '[Method] : ${options.method}\n' - '[Path] : ${options.path}\n' - '[Headers] : ${options.headers}\n' - '[Query Parameters] : ${options.queryParameters}\n' - '[Body] : ${options.data}', + '[Method] : ${options.method}\n' + '[Path] : ${options.path}\n' + '[Headers] : ${options.headers}\n' + '[Query Parameters] : ${options.queryParameters}\n' + '[Body] : ${options.data}', ); } } @@ -118,10 +118,10 @@ class DioService { var requestDuration = requestEndTime.difference(requestTimestamp); debugPrint( '\n---------------[Response - $requestTimestamp]---------------\n' - '[Status Code] : ${response.statusCode}\n' - '[Data] : ${response.data}\n' - '[Duration] : ${requestDuration.inMilliseconds} ms\n' - '----------------------------------------------\n', + '[Status Code] : ${response.statusCode}\n' + '[Data] : ${response.data}\n' + '[Duration] : ${requestDuration.inMilliseconds} ms\n' + '----------------------------------------------\n', ); } } @@ -129,10 +129,10 @@ class DioService { void logError(DioException dioException) { debugPrint( '\n---------------[Response - ERROR]---------------\n' - '[Status Code] : ${dioException.response?.statusCode}\n' - '[Message]: ${dioException.message}' - '[Data] : ${dioException.response?.data}\n' - '----------------------------------------------\n', + '[Status Code] : ${dioException.response?.statusCode}\n' + '[Message]: ${dioException.message}' + '[Data] : ${dioException.response?.data}\n' + '----------------------------------------------\n', ); } -} +} \ No newline at end of file diff --git a/lib/widgets/map/current_location_button.dart b/lib/widgets/map/current_location_button.dart index 646f922f..a99db29a 100644 --- a/lib/widgets/map/current_location_button.dart +++ b/lib/widgets/map/current_location_button.dart @@ -3,19 +3,35 @@ import 'package:get/get.dart'; import '../../constants/app_colors.dart'; import '../../controllers/map_controller.dart'; +import '../../controllers/my_place_controller.dart'; class CurrentLocationButton extends StatefulWidget { - const CurrentLocationButton({super.key}); + final String checkController; + const CurrentLocationButton({super.key, required this.checkController}); @override createState() => _CurrentLocationButtonState(); } class _CurrentLocationButtonState extends State { - final MapController mapController = Get.find(); + late final dynamic _controller; Color _buttonColor = AppColors.backgroundSecondary; // 기본 배경 색상 final Color _pressedColor = Colors.grey; // 눌렀을 때의 배경 색상 + @override + void initState(){ + super.initState(); + _initializeController(); + } + + void _initializeController(){ + if(widget.checkController=="map"){ + _controller = Get.find(); + }else{ + _controller = Get.find(); + } + } + void _onPointerDown(DragDownDetails event) { setState(() { _buttonColor = _pressedColor; @@ -32,8 +48,8 @@ class _CurrentLocationButtonState extends State { Widget build(BuildContext context) { return GestureDetector( onTap: () { - mapController.setCameraOnCurrentLocation(); - mapController.isCameraTrackingUser = true.obs; + _controller.setCameraOnCurrentLocation(); + _controller.isCameraTrackingUser = true.obs; }, onPanDown: _onPointerDown, onPanEnd: (details) => _onPointerUp(), diff --git a/lib/widgets/map/my_place_bottom_sheet.dart b/lib/widgets/map/my_place_bottom_sheet.dart index ca46a266..3a29973d 100644 --- a/lib/widgets/map/my_place_bottom_sheet.dart +++ b/lib/widgets/map/my_place_bottom_sheet.dart @@ -94,7 +94,7 @@ class MyPlaceBottomSheet extends StatelessWidget { '장소등록', style: TextStyle( fontSize: 20, - color: AppColors.textPrimary, + color: AppColors.textBlack, fontWeight: FontWeight.w700, ), ),