Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-23266] Support com.example.* package requires #28

Closed
wants to merge 2 commits into from

Conversation

sgtcoolguy
Copy link
Contributor

@sgtcoolguy sgtcoolguy commented May 6, 2016

This is to support a require syntax that uses package wildcards. I tested by changing the alert.js from hyperloop-examples to use the new syntax:

(function (container) {
    var AndroidAppPkg = require('android.app.*'),
        AlertDialog = AndroidAppPkg.AlertDialog,
        Builder = AlertDialog.Builder,
        Activity = AndroidAppPkg.Activity,
        OnClickListener = require('android.content.DialogInterface.OnClickListener');

    $.button.addEventListener('click', function () {
        var builder = new Builder(new Activity(Titanium.App.Android.getTopActivity()));
        builder.setTitle('My Title').setMessage('My Message').setCancelable(false); // modal
        builder.setPositiveButton('OK', new OnClickListener({
            onClick: function(d, which) {
                $.notice.setText('Clicked!');
            }
        }));
        builder.create().show();
    });

})($.alert_container);

A notable change here is that I now generate JS wrappers for packages. Before I'd hang js wrappers for types off the enclosing class (for nested types), or by chaining off global by building up the full namespace/package name.

Now we generate JS files for each package, i.e. android.js, android.app.js

Those package wrappers are just plain JS objects with property getters for any types contained inside (that are also referenced by the user in their app).

Some examples (I'm truncating them a little of extra newlines/comments:
android.js

var parent = global;

/**
 * Java Package exposed in JS.
 * http://developer.android.com/reference/android/package-summary.html
 **/
var android = {};
parent.android = android;

// export the interface
module.exports = android;

android.app.js

var parent = require('android') || {};

/**
 * Java Package exposed in JS.
 * http://developer.android.com/reference/android/app/package-summary.html
 **/
var app = {};
parent.app = app;

// Types in package
Object.defineProperty(app, 'ActionBar', {
    get: function() {
        return require('android.app.ActionBar');
    },
    enumerable: true
});
Object.defineProperty(app, 'Activity', {
    get: function() {
        return require('android.app.Activity');
    },
    enumerable: true
});
Object.defineProperty(app, 'ActivityGroup', {
    get: function() {
        return require('android.app.ActivityGroup');
    },
    enumerable: true
});
Object.defineProperty(app, 'ActivityManager', {
    get: function() {
        return require('android.app.ActivityManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'ActivityOptions', {
    get: function() {
        return require('android.app.ActivityOptions');
    },
    enumerable: true
});
Object.defineProperty(app, 'AlarmManager', {
    get: function() {
        return require('android.app.AlarmManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'AlertDialog', {
    get: function() {
        return require('android.app.AlertDialog');
    },
    enumerable: true
});
Object.defineProperty(app, 'AliasActivity', {
    get: function() {
        return require('android.app.AliasActivity');
    },
    enumerable: true
});
Object.defineProperty(app, 'AppOpsManager', {
    get: function() {
        return require('android.app.AppOpsManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'Application', {
    get: function() {
        return require('android.app.Application');
    },
    enumerable: true
});
Object.defineProperty(app, 'ApplicationErrorReport', {
    get: function() {
        return require('android.app.ApplicationErrorReport');
    },
    enumerable: true
});
Object.defineProperty(app, 'DatePickerDialog', {
    get: function() {
        return require('android.app.DatePickerDialog');
    },
    enumerable: true
});
Object.defineProperty(app, 'Dialog', {
    get: function() {
        return require('android.app.Dialog');
    },
    enumerable: true
});
Object.defineProperty(app, 'DialogFragment', {
    get: function() {
        return require('android.app.DialogFragment');
    },
    enumerable: true
});
Object.defineProperty(app, 'DownloadManager', {
    get: function() {
        return require('android.app.DownloadManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'ExpandableListActivity', {
    get: function() {
        return require('android.app.ExpandableListActivity');
    },
    enumerable: true
});
Object.defineProperty(app, 'Fragment', {
    get: function() {
        return require('android.app.Fragment');
    },
    enumerable: true
});
Object.defineProperty(app, 'FragmentBreadCrumbs', {
    get: function() {
        return require('android.app.FragmentBreadCrumbs');
    },
    enumerable: true
});
Object.defineProperty(app, 'FragmentContainer', {
    get: function() {
        return require('android.app.FragmentContainer');
    },
    enumerable: true
});
Object.defineProperty(app, 'FragmentController', {
    get: function() {
        return require('android.app.FragmentController');
    },
    enumerable: true
});
Object.defineProperty(app, 'FragmentHostCallback', {
    get: function() {
        return require('android.app.FragmentHostCallback');
    },
    enumerable: true
});
Object.defineProperty(app, 'FragmentManager', {
    get: function() {
        return require('android.app.FragmentManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'FragmentTransaction', {
    get: function() {
        return require('android.app.FragmentTransaction');
    },
    enumerable: true
});
Object.defineProperty(app, 'Instrumentation', {
    get: function() {
        return require('android.app.Instrumentation');
    },
    enumerable: true
});
Object.defineProperty(app, 'IntentService', {
    get: function() {
        return require('android.app.IntentService');
    },
    enumerable: true
});
Object.defineProperty(app, 'KeyguardManager', {
    get: function() {
        return require('android.app.KeyguardManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'LauncherActivity', {
    get: function() {
        return require('android.app.LauncherActivity');
    },
    enumerable: true
});
Object.defineProperty(app, 'ListActivity', {
    get: function() {
        return require('android.app.ListActivity');
    },
    enumerable: true
});
Object.defineProperty(app, 'ListFragment', {
    get: function() {
        return require('android.app.ListFragment');
    },
    enumerable: true
});
Object.defineProperty(app, 'LoaderManager', {
    get: function() {
        return require('android.app.LoaderManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'LocalActivityManager', {
    get: function() {
        return require('android.app.LocalActivityManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'MediaRouteActionProvider', {
    get: function() {
        return require('android.app.MediaRouteActionProvider');
    },
    enumerable: true
});
Object.defineProperty(app, 'MediaRouteButton', {
    get: function() {
        return require('android.app.MediaRouteButton');
    },
    enumerable: true
});
Object.defineProperty(app, 'NativeActivity', {
    get: function() {
        return require('android.app.NativeActivity');
    },
    enumerable: true
});
Object.defineProperty(app, 'Notification', {
    get: function() {
        return require('android.app.Notification');
    },
    enumerable: true
});
Object.defineProperty(app, 'NotificationManager', {
    get: function() {
        return require('android.app.NotificationManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'PendingIntent', {
    get: function() {
        return require('android.app.PendingIntent');
    },
    enumerable: true
});
Object.defineProperty(app, 'Presentation', {
    get: function() {
        return require('android.app.Presentation');
    },
    enumerable: true
});
Object.defineProperty(app, 'ProgressDialog', {
    get: function() {
        return require('android.app.ProgressDialog');
    },
    enumerable: true
});
Object.defineProperty(app, 'RemoteInput', {
    get: function() {
        return require('android.app.RemoteInput');
    },
    enumerable: true
});
Object.defineProperty(app, 'SearchManager', {
    get: function() {
        return require('android.app.SearchManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'SearchableInfo', {
    get: function() {
        return require('android.app.SearchableInfo');
    },
    enumerable: true
});
Object.defineProperty(app, 'Service', {
    get: function() {
        return require('android.app.Service');
    },
    enumerable: true
});
Object.defineProperty(app, 'SharedElementCallback', {
    get: function() {
        return require('android.app.SharedElementCallback');
    },
    enumerable: true
});
Object.defineProperty(app, 'TabActivity', {
    get: function() {
        return require('android.app.TabActivity');
    },
    enumerable: true
});
Object.defineProperty(app, 'TaskStackBuilder', {
    get: function() {
        return require('android.app.TaskStackBuilder');
    },
    enumerable: true
});
Object.defineProperty(app, 'TimePickerDialog', {
    get: function() {
        return require('android.app.TimePickerDialog');
    },
    enumerable: true
});
Object.defineProperty(app, 'UiAutomation', {
    get: function() {
        return require('android.app.UiAutomation');
    },
    enumerable: true
});
Object.defineProperty(app, 'UiModeManager', {
    get: function() {
        return require('android.app.UiModeManager');
    },
    enumerable: true
});
Object.defineProperty(app, 'VoiceInteractor', {
    get: function() {
        return require('android.app.VoiceInteractor');
    },
    enumerable: true
});
Object.defineProperty(app, 'WallpaperInfo', {
    get: function() {
        return require('android.app.WallpaperInfo');
    },
    enumerable: true
});
Object.defineProperty(app, 'WallpaperManager', {
    get: function() {
        return require('android.app.WallpaperManager');
    },
    enumerable: true
});

// export the interface
module.exports = app;

@sgtcoolguy
Copy link
Contributor Author

Given that we now generate JS wrappers for the packages, I might want to change the naming scheme. It currently reflects the exact package name, but there could easily be clashes in the top-level packages like android.js or java.js. (i.e. the user or a library could have a file named the same, and then I'm not sure what would get loaded by the hyperloop wrappers). Maybe com.example.package.js, android.package.js, android.app.package.js? Maybe if all the hyperloop wrappers use relative requires it wouldn't be an issue?

@hansemannn
Copy link
Contributor

CR + FT passed, PR approved! Since this is a feature, please bump the version to 1.2.0 and we can merge.

@sgtcoolguy
Copy link
Contributor Author

sgtcoolguy commented May 9, 2016

I wasn't sure how we wanted to handle versioning, especially with a feature implemented in Android but not iOS...

@hansemannn
Copy link
Contributor

Comprehensible concern. I think we won't be able to implement every feature for both iOS and Android, since there are many possible features that are simply platform-dependent. Is there a best practice you can recommend?

@sgtcoolguy
Copy link
Contributor Author

It still makes sense to do semantic versioning, even if the feature is specific to one platform. I was more reacting to a couple things:

  • we should try to keep parity here, so Ideally we'd get the require feature for iOS done before we release next
  • We're a little looser with branching/versioning with this module now than say the SDK. My concern is if we keep bumping the version every time we implement a bugfix/enhancement/feature even on one platform and the version balloons up over time here. Typically I do a version bump immediately preceding release for a project that isn't released on normal schedules like the SDK.

@sgtcoolguy
Copy link
Contributor Author

Squash merged manually.

@sgtcoolguy sgtcoolguy closed this May 9, 2016
@sgtcoolguy sgtcoolguy deleted the TIMOB-23266 branch May 9, 2016 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants