From ec96db99b28b314536a920c29ea1c53a2b9a104f Mon Sep 17 00:00:00 2001 From: Colleen Date: Tue, 5 Nov 2019 15:20:55 -0800 Subject: [PATCH 1/2] add mobile clean code helpers --- src/helpers/clean-android-activity.js | 16 ++ src/helpers/clean-ios-view-controller.js | 19 ++ tests/clean-android-activity.test.js | 283 +++++++++++++++++++++++ tests/clean-ios-view-controller.test.js | 114 +++++++++ 4 files changed, 432 insertions(+) create mode 100644 src/helpers/clean-android-activity.js create mode 100644 src/helpers/clean-ios-view-controller.js create mode 100644 tests/clean-android-activity.test.js create mode 100644 tests/clean-ios-view-controller.test.js diff --git a/src/helpers/clean-android-activity.js b/src/helpers/clean-android-activity.js new file mode 100644 index 000000000..8f5caa9ca --- /dev/null +++ b/src/helpers/clean-android-activity.js @@ -0,0 +1,16 @@ +function cleanAndroidActivity(content) { + let sanitizedCode; + if (content.match(/public class (\w+Activity) extends/)) { + const activityName = content.match(/public class (\w+Activity) extends/)[1]; + const activityNameRegEx = new RegExp(activityName, 'g'); + sanitizedCode = content.replace(activityNameRegEx, 'MainActivity'); + } + if (sanitizedCode && sanitizedCode.match(/R.layout.(activity[_\w]+)/)) { + const layoutName = sanitizedCode.match(/R.layout.(activity[_\w]+)/)[1]; + const layoutNameRegEx = new RegExp(layoutName, 'g'); + sanitizedCode = sanitizedCode.replace(layoutNameRegEx, 'activity_main'); + } + return sanitizedCode || content; +} + +export { cleanAndroidActivity }; diff --git a/src/helpers/clean-ios-view-controller.js b/src/helpers/clean-ios-view-controller.js new file mode 100644 index 000000000..96bafe7b0 --- /dev/null +++ b/src/helpers/clean-ios-view-controller.js @@ -0,0 +1,19 @@ +function cleanIosViewController(content) { + let namingPattern = /\n?NSString \*?const \*?MBXExample\w+ = @"(\w+)";\n?\s+?/; + if (/@objc\((\w+)\)\n?\s+?/.test(content)) + namingPattern = /@objc\((\w+)\)\n?\s+?/; + if (content.match(namingPattern)) { + const removeLine = content.replace(namingPattern, ''); + const viewControllerName = content.match(namingPattern)[1]; + const viewControllerNameRegEx = new RegExp(viewControllerName, 'g'); + const sanitizedCode = removeLine.replace( + viewControllerNameRegEx, + 'ViewController' + ); + return sanitizedCode; + } else { + return content; + } +} + +export { cleanIosViewController }; diff --git a/tests/clean-android-activity.test.js b/tests/clean-android-activity.test.js new file mode 100644 index 000000000..298af2a97 --- /dev/null +++ b/tests/clean-android-activity.test.js @@ -0,0 +1,283 @@ +'use strict'; + +const { + cleanAndroidActivity +} = require('../src/helpers/clean-android-activity.js'); + +describe('java', () => { + const sampleCode = ` +package com.mapbox.mapboxandroiddemo.examples.styles; + +import android.graphics.BitmapFactory; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.FeatureCollection; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxandroiddemo.R; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.layers.PropertyFactory; +import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; + +import java.util.ArrayList; +import java.util.List; + +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset; + +/** + * Display {@link SymbolLayer} icons on the map. + */ +public class BasicSymbolLayerActivity extends AppCompatActivity implements +OnMapReadyCallback { + +private static final String SOURCE_ID = "SOURCE_ID"; +private static final String ICON_ID = "ICON_ID"; +private static final String LAYER_ID = "LAYER_ID"; +private MapView mapView; + +@Override +protected void onCreate(Bundle savedInstanceState) { +super.onCreate(savedInstanceState); + +// Mapbox access token is configured here. This needs to be called either in your application +// object or in the same activity which contains the mapview. +Mapbox.getInstance(this, getString(R.string.access_token)); + +// This contains the MapView in XML and needs to be called after the access token is configured. +setContentView(R.layout.activity_style_basic_symbol_layer); + +mapView = findViewById(R.id.mapView); +mapView.onCreate(savedInstanceState); +mapView.getMapAsync(this); +} + +@Override +public void onMapReady(@NonNull final MapboxMap mapboxMap) { + +List symbolLayerIconFeatureList = new ArrayList<>(); +symbolLayerIconFeatureList.add(Feature.fromGeometry( +Point.fromLngLat(-57.225365, -33.213144))); +symbolLayerIconFeatureList.add(Feature.fromGeometry( +Point.fromLngLat(-54.14164, -33.981818))); +symbolLayerIconFeatureList.add(Feature.fromGeometry( +Point.fromLngLat(-56.990533, -30.583266))); + +mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cjf4m44iw0uza2spb3q0a7s41") + +// Add the SymbolLayer icon image to the map style +.withImage(ICON_ID, BitmapFactory.decodeResource( +BasicSymbolLayerActivity.this.getResources(), R.drawable.red_marker)) + +// Adding a GeoJson source for the SymbolLayer icons. +.withSource(new GeoJsonSource(SOURCE_ID, +FeatureCollection.fromFeatures(symbolLayerIconFeatureList))) + +// Adding the actual SymbolLayer to the map style. An offset is added that the bottom of the red +// marker icon gets fixed to the coordinate, rather than the middle of the icon being fixed to +// the coordinate point. This is offset is not always needed and is dependent on the image +// that you use for the SymbolLayer icon. +.withLayer(new SymbolLayer(LAYER_ID, SOURCE_ID) +.withProperties(PropertyFactory.iconImage(ICON_ID), +iconAllowOverlap(true), +iconOffset(new Float[] {0f, -9f})) +), new Style.OnStyleLoaded() { +@Override +public void onStyleLoaded(@NonNull Style style) { + +// Map is set up and the style has loaded. Now you can add additional data or make other map adjustments. + + +} +}); +} + +@Override +public void onResume() { +super.onResume(); +mapView.onResume(); +} + +@Override +protected void onStart() { +super.onStart(); +mapView.onStart(); +} + +@Override +protected void onStop() { +super.onStop(); +mapView.onStop(); +} + +@Override +public void onPause() { +super.onPause(); +mapView.onPause(); +} + +@Override +public void onLowMemory() { +super.onLowMemory(); +mapView.onLowMemory(); +} + +@Override +protected void onDestroy() { +super.onDestroy(); +mapView.onDestroy(); +} + +@Override +protected void onSaveInstanceState(Bundle outState) { +super.onSaveInstanceState(outState); +mapView.onSaveInstanceState(outState); +} +}`; + + test(`javaClean`, () => { + expect(cleanAndroidActivity(sampleCode)).toEqual(` +package com.mapbox.mapboxandroiddemo.examples.styles; + +import android.graphics.BitmapFactory; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.FeatureCollection; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxandroiddemo.R; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.layers.PropertyFactory; +import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; + +import java.util.ArrayList; +import java.util.List; + +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset; + +/** + * Display {@link SymbolLayer} icons on the map. + */ +public class MainActivity extends AppCompatActivity implements +OnMapReadyCallback { + +private static final String SOURCE_ID = "SOURCE_ID"; +private static final String ICON_ID = "ICON_ID"; +private static final String LAYER_ID = "LAYER_ID"; +private MapView mapView; + +@Override +protected void onCreate(Bundle savedInstanceState) { +super.onCreate(savedInstanceState); + +// Mapbox access token is configured here. This needs to be called either in your application +// object or in the same activity which contains the mapview. +Mapbox.getInstance(this, getString(R.string.access_token)); + +// This contains the MapView in XML and needs to be called after the access token is configured. +setContentView(R.layout.activity_main); + +mapView = findViewById(R.id.mapView); +mapView.onCreate(savedInstanceState); +mapView.getMapAsync(this); +} + +@Override +public void onMapReady(@NonNull final MapboxMap mapboxMap) { + +List symbolLayerIconFeatureList = new ArrayList<>(); +symbolLayerIconFeatureList.add(Feature.fromGeometry( +Point.fromLngLat(-57.225365, -33.213144))); +symbolLayerIconFeatureList.add(Feature.fromGeometry( +Point.fromLngLat(-54.14164, -33.981818))); +symbolLayerIconFeatureList.add(Feature.fromGeometry( +Point.fromLngLat(-56.990533, -30.583266))); + +mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cjf4m44iw0uza2spb3q0a7s41") + +// Add the SymbolLayer icon image to the map style +.withImage(ICON_ID, BitmapFactory.decodeResource( +MainActivity.this.getResources(), R.drawable.red_marker)) + +// Adding a GeoJson source for the SymbolLayer icons. +.withSource(new GeoJsonSource(SOURCE_ID, +FeatureCollection.fromFeatures(symbolLayerIconFeatureList))) + +// Adding the actual SymbolLayer to the map style. An offset is added that the bottom of the red +// marker icon gets fixed to the coordinate, rather than the middle of the icon being fixed to +// the coordinate point. This is offset is not always needed and is dependent on the image +// that you use for the SymbolLayer icon. +.withLayer(new SymbolLayer(LAYER_ID, SOURCE_ID) +.withProperties(PropertyFactory.iconImage(ICON_ID), +iconAllowOverlap(true), +iconOffset(new Float[] {0f, -9f})) +), new Style.OnStyleLoaded() { +@Override +public void onStyleLoaded(@NonNull Style style) { + +// Map is set up and the style has loaded. Now you can add additional data or make other map adjustments. + + +} +}); +} + +@Override +public void onResume() { +super.onResume(); +mapView.onResume(); +} + +@Override +protected void onStart() { +super.onStart(); +mapView.onStart(); +} + +@Override +protected void onStop() { +super.onStop(); +mapView.onStop(); +} + +@Override +public void onPause() { +super.onPause(); +mapView.onPause(); +} + +@Override +public void onLowMemory() { +super.onLowMemory(); +mapView.onLowMemory(); +} + +@Override +protected void onDestroy() { +super.onDestroy(); +mapView.onDestroy(); +} + +@Override +protected void onSaveInstanceState(Bundle outState) { +super.onSaveInstanceState(outState); +mapView.onSaveInstanceState(outState); +} +}`); + }); +}); diff --git a/tests/clean-ios-view-controller.test.js b/tests/clean-ios-view-controller.test.js new file mode 100644 index 000000000..d80c809c2 --- /dev/null +++ b/tests/clean-ios-view-controller.test.js @@ -0,0 +1,114 @@ +'use strict'; + +const { + cleanIosViewController +} = require('../src/helpers/clean-ios-view-controller.js'); + +describe('swift', () => { + const sampleCode = ` +import Mapbox + +@objc(StudioStyleExample_Swift) + +class StudioStyleExample_Swift: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + // Replace the string in the URL below with your custom style URL from Mapbox Studio. + // Read more about style URLs here: https://www.mapbox.com/help/define-style-url/ + let styleURL = URL(string: "mapbox://styles/mapbox/outdoors-v9") + let mapView = MGLMapView(frame: view.bounds, + styleURL: styleURL) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + // Set the map’s center coordinate and zoom level. + mapView.setCenter(CLLocationCoordinate2D(latitude: 45.52954, + longitude: -122.72317), + zoomLevel: 14, animated: false) + view.addSubview(mapView) + } +}`; + + test(`swiftClean`, () => { + expect(cleanIosViewController(sampleCode)).toEqual(` +import Mapbox + +class ViewController: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + // Replace the string in the URL below with your custom style URL from Mapbox Studio. + // Read more about style URLs here: https://www.mapbox.com/help/define-style-url/ + let styleURL = URL(string: "mapbox://styles/mapbox/outdoors-v9") + let mapView = MGLMapView(frame: view.bounds, + styleURL: styleURL) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + // Set the map’s center coordinate and zoom level. + mapView.setCenter(CLLocationCoordinate2D(latitude: 45.52954, + longitude: -122.72317), + zoomLevel: 14, animated: false) + view.addSubview(mapView) + } +}`); + }); +}); + +describe('ojective-c', () => { + const sampleCode = ` +#import "StudioStyleExample.h" +@import Mapbox; + +NSString *const MBXExampleStudioStyle = @"StudioStyleExample"; + +@implementation StudioStyleExample + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Replace the string in the URL below with your custom style URL from Mapbox Studio. + // Read more about style URLs here: https://www.mapbox.com/help/define-style-url/ + NSURL *styleURL = [NSURL URLWithString:@"mapbox://styles/mapbox/outdoors-v9"]; + MGLMapView *mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds + styleURL:styleURL]; + + mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + // Set the map’s center coordinate and zoom level. + [mapView setCenterCoordinate:CLLocationCoordinate2DMake(45.52954, -122.72317) + zoomLevel:14 + animated:NO]; + + [self.view addSubview:mapView]; +} + +@end`; + + test(`objClean`, () => { + expect(cleanIosViewController(sampleCode)).toEqual(` +#import "ViewController.h" +@import Mapbox; +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Replace the string in the URL below with your custom style URL from Mapbox Studio. + // Read more about style URLs here: https://www.mapbox.com/help/define-style-url/ + NSURL *styleURL = [NSURL URLWithString:@"mapbox://styles/mapbox/outdoors-v9"]; + MGLMapView *mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds + styleURL:styleURL]; + + mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + // Set the map’s center coordinate and zoom level. + [mapView setCenterCoordinate:CLLocationCoordinate2DMake(45.52954, -122.72317) + zoomLevel:14 + animated:NO]; + + [self.view addSubview:mapView]; +} + +@end`); + }); +}); From 700460e578c9be8ba654221e53cc75d6f98bcc54 Mon Sep 17 00:00:00 2001 From: Colleen Date: Wed, 13 Nov 2019 11:30:03 -0800 Subject: [PATCH 2/2] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1b5239d8..3533d8a03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Add `GlossaryCard`, `GlossarySection`, and `GlossaryPage` components. [#192](https://github.com/mapbox/dr-ui/pull/192) * Creates new theme for `Search` button. [#189](https://github.com/mapbox/dr-ui/pull/189) * Add `Phone` component. [#195](https://github.com/mapbox/dr-ui/pull/195) +* Add `cleanAndroidActivity` and `cleanIosViewController` helper functions. [#194](https://github.com/mapbox/dr-ui/pull/194) ## 0.21.2