mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Display user heading in location picker and location view
This commit is contained in:
parent
3fbb7bf303
commit
3c0afd30d4
@ -71,6 +71,8 @@
|
||||
bool _throttle;
|
||||
TGLocationPinAnnotationView *_ownLiveLocationView;
|
||||
__weak MKAnnotationView *_userLocationView;
|
||||
|
||||
UIImageView *_headingArrowView;
|
||||
}
|
||||
@end
|
||||
|
||||
@ -162,6 +164,8 @@
|
||||
[_liveLocationsDisposable dispose];
|
||||
[_reloadDisposable dispose];
|
||||
[_frequentUpdatesDisposable dispose];
|
||||
|
||||
[_locationManager stopUpdatingHeading];
|
||||
}
|
||||
|
||||
- (void)tg_setRightBarButtonItem:(UIBarButtonItem *)barButtonItem action:(bool)action animated:(bool)animated {
|
||||
@ -438,6 +442,36 @@
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
static UIImage *headingArrowImage = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(28.0f, 28.0f), false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextClearRect(context, CGRectMake(0, 0, 28, 28));
|
||||
|
||||
CGContextSetFillColorWithColor(context, UIColorRGB(0x3393fe).CGColor);
|
||||
|
||||
CGContextMoveToPoint(context, 14, 0);
|
||||
CGContextAddLineToPoint(context, 19, 7);
|
||||
CGContextAddLineToPoint(context, 9, 7);
|
||||
CGContextClosePath(context);
|
||||
CGContextFillPath(context);
|
||||
|
||||
CGContextSetBlendMode(context, kCGBlendModeClear);
|
||||
CGContextFillEllipseInRect(context, CGRectMake(5.0, 5.0, 18.0, 18.0));
|
||||
|
||||
headingArrowImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
});
|
||||
|
||||
_headingArrowView = [[UIImageView alloc] init];
|
||||
_headingArrowView.hidden = true;
|
||||
_headingArrowView.frame = CGRectMake(0.0, 0.0, 28.0, 28.0);
|
||||
_headingArrowView.image = headingArrowImage;
|
||||
|
||||
_tableView.scrollsToTop = false;
|
||||
_mapView.tapEnabled = false;
|
||||
|
||||
@ -495,6 +529,8 @@
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
[_locationManager startUpdatingHeading];
|
||||
|
||||
if (self.previewMode && !animated)
|
||||
{
|
||||
UIView *contentView = [[_mapView subviews] firstObject];
|
||||
@ -950,6 +986,9 @@
|
||||
{
|
||||
_userLocationView = view;
|
||||
|
||||
[_userLocationView addSubview:_headingArrowView];
|
||||
_headingArrowView.center = CGPointMake(view.frame.size.width / 2.0, view.frame.size.height / 2.0);
|
||||
|
||||
if (_ownLiveLocationView != nil)
|
||||
{
|
||||
[_userLocationView addSubview:_ownLiveLocationView];
|
||||
@ -982,6 +1021,14 @@
|
||||
return CLLocationCoordinate2DMake(_locationAttachment.latitude, _locationAttachment.longitude);
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
|
||||
{
|
||||
if (newHeading != nil) {
|
||||
_headingArrowView.hidden = false;
|
||||
_headingArrowView.transform = CGAffineTransformMakeRotation(newHeading.magneticHeading / 180.0 * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
|
@ -68,11 +68,30 @@ private class LocationMapView: MKMapView, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private func generateHeadingArrowImage() -> UIImage? {
|
||||
return generateImage(CGSize(width: 28.0, height: 28.0)) { size, context in
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
context.clear(bounds)
|
||||
|
||||
context.setFillColor(UIColor(rgb: 0x3393fe).cgColor)
|
||||
|
||||
context.move(to: CGPoint(x: 14.0, y: 0.0))
|
||||
context.addLine(to: CGPoint(x: 19.0, y: 7.0))
|
||||
context.addLine(to: CGPoint(x: 9.0, y: 7.0))
|
||||
context.closePath()
|
||||
context.fillPath()
|
||||
|
||||
context.setBlendMode(.clear)
|
||||
context.fillEllipse(in: bounds.insetBy(dx: 5.0, dy: 5.0))
|
||||
}
|
||||
}
|
||||
|
||||
final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
private let locationPromise = Promise<CLLocation?>(nil)
|
||||
|
||||
private let pickerAnnotationContainerView: PickerAnnotationContainerView
|
||||
private weak var userLocationAnnotationView: MKAnnotationView?
|
||||
private var headingArrowView: UIImageView?
|
||||
|
||||
private let pinDisposable = MetaDisposable()
|
||||
|
||||
@ -103,6 +122,10 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.headingArrowView = UIImageView()
|
||||
self.headingArrowView?.frame = CGRect(origin: CGPoint(), size: CGSize(width: 28.0, height: 28.0))
|
||||
self.headingArrowView?.image = generateHeadingArrowImage()
|
||||
|
||||
self.mapView?.interactiveTransitionGestureRecognizerTest = { p in
|
||||
if p.x > 44.0 {
|
||||
return true
|
||||
@ -232,6 +255,10 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
for view in views {
|
||||
if view.annotation is MKUserLocation {
|
||||
self.userLocationAnnotationView = view
|
||||
if let headingArrowView = self.headingArrowView {
|
||||
view.addSubview(headingArrowView)
|
||||
headingArrowView.center = CGPoint(x: view.frame.width / 2.0, y: view.frame.height / 2.0)
|
||||
}
|
||||
if let annotationView = self.customUserLocationAnnotationView {
|
||||
view.addSubview(annotationView)
|
||||
}
|
||||
@ -347,6 +374,18 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
var userHeading: CGFloat? = nil {
|
||||
didSet {
|
||||
if let heading = self.userHeading {
|
||||
self.headingArrowView?.isHidden = false
|
||||
self.headingArrowView?.transform = CGAffineTransform(rotationAngle: CGFloat(heading / 180.0 * CGFloat.pi))
|
||||
} else {
|
||||
self.headingArrowView?.isHidden = true
|
||||
self.headingArrowView?.transform = CGAffineTransform.identity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var annotations: [LocationPinAnnotation] = [] {
|
||||
didSet {
|
||||
guard let mapView = self.mapView else {
|
||||
|
@ -289,7 +289,7 @@ public final class LocationPickerController: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
self.displayNode = LocationPickerControllerNode(context: self.context, presentationData: self.presentationData, mode: self.mode, interaction: interaction)
|
||||
self.displayNode = LocationPickerControllerNode(context: self.context, presentationData: self.presentationData, mode: self.mode, interaction: interaction, locationManager: self.locationManager)
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
self.permissionDisposable = (DeviceAccess.authorizationStatus(subject: .location(.send))
|
||||
|
@ -17,6 +17,7 @@ import AppBundle
|
||||
import CoreLocation
|
||||
import Geocoding
|
||||
import PhoneNumberFormat
|
||||
import DeviceAccess
|
||||
|
||||
private struct LocationPickerTransaction {
|
||||
let deletions: [ListViewDeleteItem]
|
||||
@ -240,12 +241,13 @@ struct LocationPickerState {
|
||||
}
|
||||
}
|
||||
|
||||
final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationManagerDelegate {
|
||||
private let context: AccountContext
|
||||
private var presentationData: PresentationData
|
||||
private let presentationDataPromise: Promise<PresentationData>
|
||||
private let mode: LocationPickerMode
|
||||
private let interaction: LocationPickerInteraction
|
||||
private let locationManager: LocationManager
|
||||
|
||||
private let listNode: ListView
|
||||
private let emptyResultsTextNode: ImmediateTextNode
|
||||
@ -269,12 +271,13 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
private var listOffset: CGFloat?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, mode: LocationPickerMode, interaction: LocationPickerInteraction) {
|
||||
init(context: AccountContext, presentationData: PresentationData, mode: LocationPickerMode, interaction: LocationPickerInteraction, locationManager: LocationManager) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.presentationDataPromise = Promise(presentationData)
|
||||
self.mode = mode
|
||||
self.interaction = interaction
|
||||
self.locationManager = locationManager
|
||||
|
||||
self.state = LocationPickerState()
|
||||
self.statePromise = Promise(self.state)
|
||||
@ -539,7 +542,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
switch previousState.selectedLocation {
|
||||
case .none, .venue:
|
||||
updateMap = true
|
||||
case let .location(previousCoordinate, address):
|
||||
case let .location(previousCoordinate, _):
|
||||
if previousCoordinate != coordinate {
|
||||
updateMap = true
|
||||
}
|
||||
@ -691,11 +694,20 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
strongSelf.goToUserLocation()
|
||||
}
|
||||
}
|
||||
|
||||
self.locationManager.manager.startUpdatingHeading()
|
||||
self.locationManager.manager.delegate = self
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable?.dispose()
|
||||
self.geocodingDisposable.dispose()
|
||||
|
||||
self.locationManager.manager.stopUpdatingHeading()
|
||||
}
|
||||
|
||||
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
|
||||
self.headerNode.mapNode.userHeading = CGFloat(newHeading.magneticHeading)
|
||||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
@ -727,7 +739,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
private func dequeueTransition() {
|
||||
guard let layout = self.validLayout, let transition = self.enqueuedTransitions.first else {
|
||||
guard let _ = self.validLayout, let transition = self.enqueuedTransitions.first else {
|
||||
return
|
||||
}
|
||||
self.enqueuedTransitions.remove(at: 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user