From 348a6b734cef8636e2f31e1c541f3934c0f0ef57 Mon Sep 17 00:00:00 2001 From: iOS Build Date: Fri, 4 May 2012 20:59:26 -0700 Subject: [PATCH 1/6] Initial work towards the iOS port * Moving the main UI towards a tab group layout for iOS * Some small changes in the way that iOS vs Android refer to files * Conditional checks for Android when applying android styles to switches --- Resources/app.js | 52 +++++++++++++++++++++----------- Resources/march-hare/database.js | 6 +++- Resources/windows/Map.js | 15 ++++++--- Resources/windows/Settings.js | 6 ++-- tiapp.xml | 4 +-- 5 files changed, 56 insertions(+), 27 deletions(-) diff --git a/Resources/app.js b/Resources/app.js index 1973d37..7a61d21 100644 --- a/Resources/app.js +++ b/Resources/app.js @@ -1,4 +1,4 @@ -var DEV = false; +var DEV = true; var POLLING = false; Ti.App.Properties.setBool('map_initialized', false); @@ -18,12 +18,9 @@ Ti.include( var reportsInitialized = false; -var win = MarchHare.ui.createMapWindow(); - -win.open(); if (Ti.Platform.osname == 'android') { - var win = Ti.UI.currentWindow; + var win = MarchHare.ui.createMapWindow(); var activity = Ti.Android.currentActivity; activity.onCreateOptionsMenu = function(e){ @@ -39,21 +36,42 @@ if (Ti.Platform.osname == 'android') { settingsWin.open({}); }); }; + win.open(); } -/* else { - // TODO: create iOS options menu - // iOS code might look something like this: where iconWin is an actuall - // icon? I am not sure how menus are done in iOS - var rightButton = Ti.UI.createButton({ - systemButton: Ti.UI.iPhone.SystemButton.REFRESH - }); - iconWin.rightNavButton = rightButton; - rightButton.addEventListener('click', function () { - Ti.fireEvent('codestrong:update_data'); - }); + Titanium.UI.setBackgroundColor('#000'); + + // Create a tab group + var tabGroup = Titanium.UI.createTabGroup({id: 'tabGroup1'}); + + // Create Main tab + var mapTab = Titanium.UI.createTab({ + title: 'Map', + window: MarchHare.ui.createMapWindow() + }); + + // Create settings win/tab + var settingsTab = Titanium.UI.createTab({ + title: 'Settings', + window: MarchHare.ui.createSettingsWindow() + }); + + // Create reports win/tab + var reportsTab = Titanium.UI.createTab({ + title: 'Reports', + window: MarchHare.ui.createSettingsWindow() + }); + + // Add tabs + tabGroup.add(mapTab); + tabGroup.add(settingsTab); + tabGroup.add(reportsTab); + + tabGroup.setActiveTab(mapTab); + tabGroup.open({ + transition: Titanium.UI.iPhone.AnimationStyle.FLIP_FROM_LEFT + }); } -*/ // Set the handler for whe the action midpoint is recieved // In testing this event does not get recieved until after the settings are diff --git a/Resources/march-hare/database.js b/Resources/march-hare/database.js index 656554a..682385c 100644 --- a/Resources/march-hare/database.js +++ b/Resources/march-hare/database.js @@ -15,7 +15,11 @@ db = Ti.Database.install('incidents.sqllite', 'incidents'); } */ - db = Ti.Database.install('incidents.sqlite', 'incidents'); + if (Ti.Platform.name === 'android') { + db = Ti.Database.install('incidents.sqlite', 'incidents'); + } else { + db = Ti.Database.install('march-hare/incidents.sqlite', 'incidents'); + } var databaseIndicator = Titanium.UI.createActivityIndicator({ height:50, width:10 }); diff --git a/Resources/windows/Map.js b/Resources/windows/Map.js index adc6028..7431e75 100644 --- a/Resources/windows/Map.js +++ b/Resources/windows/Map.js @@ -1,9 +1,16 @@ (function () { MarchHare.ui.createMapView = function() { + var url; + if (Ti.Platform.name === 'android') { + url = '../pages/map.html'; + } else { + url = 'pages/map.html'; + } + var webview = Ti.UI.createWebView({ - url: '../pages/map.html', - touchEnabled: true - }); + url: url, + touchEnabled: true + }); // TODO: The gestures below need to be supported // https://wiki.appcelerator.org/display/guides/Supporting+Gestures @@ -34,7 +41,7 @@ MarchHare.ui.createMapWindow = function() { var win = Ti.UI.createWindow({ - title: 'In the streets', + title: 'Map', exitOnClose: true, }); diff --git a/Resources/windows/Settings.js b/Resources/windows/Settings.js index d256048..5bcc2e6 100644 --- a/Resources/windows/Settings.js +++ b/Resources/windows/Settings.js @@ -117,7 +117,7 @@ var GPSField = Ti.UI.createSwitch( { top: 5, right: 10, - style:Ti.UI.Android.SWITCH_STYLE_CHECKBOX, + style: (Titanium.Platform.osname == 'android') && Ti.UI.Android.SWITCH_STYLE_CHECKBOX, value: Ti.App.Properties.getBool('gpsFollow', MarchHare.settings.gpsFollow.default_value) }); @@ -149,7 +149,7 @@ var VibField = Ti.UI.createSwitch( { top: 5, right: 10, - style:Ti.UI.Android.SWITCH_STYLE_CHECKBOX, + style: (Titanium.Platform.osname == 'android') && Ti.UI.Android.SWITCH_STYLE_CHECKBOX, value: Ti.App.Properties.getBool('vibrate', false) }); @@ -194,7 +194,7 @@ var categorySwitch = Ti.UI.createSwitch({ top: 5, right: 10, - style:Ti.UI.Android.SWITCH_STYLE_CHECKBOX, + style: (Titanium.Platform.osname == 'android') && Ti.UI.Android.SWITCH_STYLE_CHECKBOX, category_id: categories[i].id, value: categories[i].filter ? true : false }); diff --git a/tiapp.xml b/tiapp.xml index 6ccfd83..7d21aa9 100644 --- a/tiapp.xml +++ b/tiapp.xml @@ -3,12 +3,12 @@ v8 false - false + true false true false - 1.8.2 + 2.0.1.GA2 org.marchhare.natog82012 NATO-G8 2012 Beta RC1 From 1fb630ab54f0a2fd92ed8b6109974170edb75ab1 Mon Sep 17 00:00:00 2001 From: "Mr. Evoltech" Date: Tue, 8 May 2012 00:41:55 -0700 Subject: [PATCH 2/6] Completes the port to iOS. Prolly still some bugs * Switch all Ti.API.debug to Ti.API.log * Add tabGroup navigation for iOS (we should probably switch the android version to this). This mandated a significant switch in how windows and associated events with windows affect the flow of the app. * Fix category initialization * Slight modification for how we handle newIncidents * Small but major fix for how we handle HTTPClient Responses * Small improvement to how we trigger category filter updates --- Resources/app.js | 117 ++++++++++++++++++-------- Resources/img/KS_nav_map.png | Bin 0 -> 1523 bytes Resources/img/KS_nav_ui.png | Bin 0 -> 1158 bytes Resources/img/KS_nav_views.png | Bin 0 -> 1074 bytes Resources/js/reports.js | 8 +- Resources/march-hare/database.js | 8 -- Resources/march-hare/march-hare.js | 37 +++++---- Resources/windows/Map.js | 2 +- Resources/windows/Reports.js | 128 +++++++++++++++++------------ Resources/windows/Settings.js | 45 +++++++--- tiapp.xml | 2 +- 11 files changed, 215 insertions(+), 132 deletions(-) create mode 100644 Resources/img/KS_nav_map.png create mode 100644 Resources/img/KS_nav_ui.png create mode 100644 Resources/img/KS_nav_views.png diff --git a/Resources/app.js b/Resources/app.js index 7a61d21..5a2c472 100644 --- a/Resources/app.js +++ b/Resources/app.js @@ -1,10 +1,9 @@ -var DEV = true; +var DEV = false; var POLLING = false; Ti.App.Properties.setBool('map_initialized', false); // this sets the background color of the master UIView (when there are no windows/tab groups on it) Titanium.UI.setBackgroundColor('#000'); -Ti.API.debug('including the app helpers and windows'); Ti.include( 'march-hare/march-hare.js', @@ -18,6 +17,8 @@ Ti.include( var reportsInitialized = false; +var tabGroup; +var mapTab; if (Ti.Platform.osname == 'android') { var win = MarchHare.ui.createMapWindow(); @@ -39,43 +40,74 @@ if (Ti.Platform.osname == 'android') { win.open(); } else { - Titanium.UI.setBackgroundColor('#000'); - // Create a tab group - var tabGroup = Titanium.UI.createTabGroup({id: 'tabGroup1'}); + tabGroup = Titanium.UI.createTabGroup(); // Create Main tab - var mapTab = Titanium.UI.createTab({ + var mapWin = MarchHare.ui.createMapWindow(); + mapTab = Titanium.UI.createTab({ title: 'Map', - window: MarchHare.ui.createMapWindow() - }); - - // Create settings win/tab - var settingsTab = Titanium.UI.createTab({ - title: 'Settings', - window: MarchHare.ui.createSettingsWindow() + icon: '/img/KS_nav_map.png', + window: mapWin }); // Create reports win/tab + var reportsWin = MarchHare.ui.createReportsWindow(); var reportsTab = Titanium.UI.createTab({ title: 'Reports', - window: MarchHare.ui.createSettingsWindow() + icon: '/img/KS_nav_ui.png', + window: reportsWin }); // Add tabs - tabGroup.add(mapTab); - tabGroup.add(settingsTab); - tabGroup.add(reportsTab); + tabGroup.addTab(mapTab); + tabGroup.addTab(reportsTab); tabGroup.setActiveTab(mapTab); - tabGroup.open({ - transition: Titanium.UI.iPhone.AnimationStyle.FLIP_FROM_LEFT + tabGroup.open(); + + // There is a situation where the windows here can be created before the + // incident database is populated. When there are updates to the db then + // we need to recreate these windows because they are not created dynamically + // like they are in the modal windows for android + Ti.App.addEventListener('categoriesDownloaded', function() { + // Create settings win/tab + var settingsWin = MarchHare.ui.createSettingsWindow(); + var settingsTab = Titanium.UI.createTab({ + title: 'Settings', + icon: '/img/KS_nav_views.png', + window: settingsWin + }); + tabGroup.addTab(settingsTab); + }); + + Ti.App.addEventListener('filterReports', function() { + tabGroup.removeTab(reportsTab); + reportsWin = MarchHare.ui.createReportsWindow(); + reportsTab = Titanium.UI.createTab({ + title: 'Reports', + icon: '/img/KS_nav_ui.png', + window: reportsWin + }); + tabGroup.addTab(reportsTab); + }); + + Ti.App.addEventListener('newIncidents', function() { + tabGroup.removeTab(reportsTab); + reportsWin = MarchHare.ui.createReportsWindow(); + reportsTab = Titanium.UI.createTab({ + title: 'Reports', + icon: '/img/KS_nav_ui.png', + window: reportsWin + }); + tabGroup.addTab(reportsTab); }); } // Set the handler for whe the action midpoint is recieved // In testing this event does not get recieved until after the settings are // sent to the map view +// TODO: Does this create a memory leak? Ti.App.addEventListener('geolocationDownloaded', function() { updatedActionMidPoint(); }); @@ -85,11 +117,13 @@ Ti.App.addEventListener('geolocationDownloaded', function() { // TODO: test with these settings off if (DEV) { Ti.App.Properties.setString('lastpoll', '1970-01-01'); + MarchHare.database.flushCategories(); + MarchHare.database.flushIncidentCategories(); MarchHare.database.flushIncidents(); - MarchHare.database.flushIncidentCategories(); - MarchHare.database.flushCategories(); Ti.App.Properties.setInt('poll', MarchHare.settings.poll.default_value); } + +// Force a lookup of all categories everytime the application starts MarchHare.database.initializeCategories(); MarchHare.database.initializeMidPoint(); @@ -109,7 +143,7 @@ Ti.App.addEventListener('readyForReports', function() { // recieve this event. Which means we have a race condition. The effects // of this should be investigated. Ti.App.addEventListener('actionDomainChanged', function() { - Ti.API.debug('actionDomainChanged event recieved, updating system'); + Ti.API.log('actionDomainChanged event recieved, updating system'); Ti.App.Properties.setString('lastpoll', '1970-01-01'); MarchHare.database.flushIncidents(); MarchHare.database.flushIncidentCategories(); @@ -121,9 +155,9 @@ Ti.App.addEventListener('actionDomainChanged', function() { var pollInterval; Ti.App.addEventListener('mapInitialized', function() { - Ti.API.debug('mapInitialized event recieved'); + Ti.API.log('mapInitialized event recieved'); Ti.App.Properties.setBool('map_initialized', true); - Ti.API.debug('polling for new reports every '+ + Ti.API.log('polling for new reports every '+ Ti.App.Properties.getInt('poll', MarchHare.settings.poll.default_value)*1000 + ' seconds'); pollInterval = setInterval(pollForReports, @@ -132,7 +166,7 @@ Ti.App.addEventListener('mapInitialized', function() { }); Ti.App.addEventListener('pollIntervalChanged', function() { - Ti.API.debug('pollIntervalChanged event recieved, updating poll interval'); + Ti.API.log('pollIntervalChanged event recieved, updating poll interval'); clearInterval(pollInterval); pollInterval = setInterval(pollForReports, Ti.App.Properties.getString('poll', MarchHare.settings.poll.default_value) @@ -155,14 +189,14 @@ if (Ti.App.Properties.getBool('gpsFollow', } Ti.App.addEventListener('gpsFollowChanged', function() { - Ti.API.debug('gpsFollowChanged ('+ + Ti.API.log('gpsFollowChanged ('+ Ti.App.Properties.getBool('gpsFollow', 'NOT SET')+ ') event recieved, updating location polling'); if (Ti.App.Properties.getBool('gpsFollow', MarchHare.settings.gpsFollow.default_value)) { Titanium.Geolocation.addEventListener('location', updateGeoLocationHandler); } else { - Ti.API.debug('gpsFollowChanged event recieved, clearing gps interval'); + Ti.API.log('gpsFollowChanged event recieved, clearing gps interval'); // This handles the privacy concern of a user turning off gpsFollow on // their device then getting their phone confiscated and the saved location @@ -177,7 +211,7 @@ Ti.App.addEventListener('gpsFollowChanged', function() { }); function updateGeoLocationHandler(location) { - Ti.API.debug('app.js::updateGeoLocationHandler() location: '+ + Ti.API.log('app.js::updateGeoLocationHandler() location: '+ JSON.stringify(location)); // Titanium.Geolocation.location: http://bit.ly/GG6qri @@ -206,7 +240,7 @@ function updateGeoLocation() { }); if( Titanium.Geolocation.locationServicesEnabled === false ) { - Ti.API.debug('app.js::updateGeoLocation() device has GPS turned off.'); + Ti.API.log('app.js::updateGeoLocation() device has GPS turned off.'); alert.message = 'Your device has GPS turned off. Please turn it on.'; alert.show(); setTimeout(function() { @@ -225,7 +259,7 @@ function updateGeoLocation() { return; } - Ti.API.debug('app.js::updateGeoLocation location: '+ + Ti.API.log('app.js::updateGeoLocation location: '+ JSON.stringify(location.coords)); // TODO: saving geo location on the device could be // a privacy concern. Can we get around this? For @@ -338,18 +372,17 @@ function handleServerResponse(response) { } if (newIncidents || !initialized) { - Ti.API.debug('pollReports: firing updateReports event, map_initialized: '+ + Ti.API.log('pollReports: firing updateReports event, map_initialized: '+ initialized +', newIncidents: '+ newIncidents); updatedReportsAction(); } else { - Ti.API.debug('pollReports: not updating because we did not recieve any new reports'); + Ti.API.log('pollReports: not updating because we did not recieve any new reports'); } - // Create a notification if we recieved new incidents - if (newIncidents && Ti.App.Properties.getBool('vibrate', false)) { - Ti.API.debug('pollReports: triggering an alert'); - Titanium.Media.vibrate(); + // Let other interested parties do what they want with newIncidents + if (newIncidents) { + Ti.App.fireEvent('newIncidents'); } if (!error) { @@ -358,9 +391,21 @@ function handleServerResponse(response) { } Ti.App.addEventListener('filterReports', function() { + Ti.API.log('filterReports event recieved'); updatedReportsAction(); }); +Ti.App.addEventListener('newIncidents', function() { + notifyUser(); +}); + +function notifyUser() { + if (Ti.App.Properties.getBool('vibrate', false)) { + Ti.API.log('Vibrating the phone'); + Titanium.Media.vibrate(); + } +} + function updatedReportsAction() { result = MarchHare.database.getIncidentsJSON({}); diff --git a/Resources/img/KS_nav_map.png b/Resources/img/KS_nav_map.png new file mode 100644 index 0000000000000000000000000000000000000000..959686fc200d547eaf1547c9fde7cf4327413a9f GIT binary patch literal 1523 zcmVJUfYYo zE>BEM?Ct96IwNDj!NHfVEw9F~6)8Y+fNR#()xB?SZl1;Ea)orD^7?~=gTeLn_0RAC zO<3bp)xdQ-IyxSjn3&urYbXL(w%^>`{3bRwHU(>)r~)`UEiKI=E-tPOZec40O)MiL zW39Qlc@c9Y(ipO|wB*~{+Z+1%`5F26_~_{A>9M82i5(vw&o(qPgqD<){7JAX6Zq|c zfq@|&k0+o5*x1;RgocKGj`2R2m=;5Pm^ti@zP`RoQc{vIGBT1+e_*)ILR3_g2j)Ce z6!=xMif&6wO9`LP7sw6_4Gk@$Ylr=WqN1XNtgno8s99WG94inA?!9afF4BeWui@cgshhCyWzPHi`%n7%`nGU7Nj=!N z22nYZWPN=mfoo)DX5KY5HMPHN0J~=u0F4>PM;9QYNbYFV1wzl@ts6ocCb#QQ~M{((cxp;bdzOcT(zdr|{ zAK2R3mfG0Zyo;>#p9geyb|(99nF4NTW@hFtJ&BKxUy(N%8Alit6f{y(Q}cOo1Eq6=a0)26-@&J1H-HAcjMrspXBA`rNBS6pmdU{h69RX@`&ayXn{(dEN(_xAR_K<22Qo12qd z7kGVrJz0N>+K&<7Bv@A9E|1aHr5D4(!U(76g*_pRZ)azx65ziF3lv`!bZcwtI^5(j z*+-G!yov%M8ORRyQBzY>8c32h$qvXiH4qICva+%^h&qCaV1(g060!sa$b*=^4N7bj z9UaY+m2Siq7Z?9dNJuEa{A$>YR6sK+-H1XFfe0l*2z&@pp-t|WNF>KwTU%w|FL^mR zIpi~&5!yk`=TgV^puW+msi`(};0p^262!`PySuxknDaYbI5Vy}VZN}K+}zv`Vq#(p z=_((-{^aE3WE5QG4+!CB$loF@EiHG*GjALl(p5fOZ@;jx@CU3_N4cEBn)6yJpAx_> zu=j$4gQFmT@4yvw6#Xqh= zYinzcEMR1t(~*%8F~s%~(&}&28z%jts{X6UQU=1W-zGi`dj}?<+OhU Z7yyC+B6og5o2LK(002ovPDHLkV1g13=nwz^ literal 0 HcmV?d00001 diff --git a/Resources/img/KS_nav_ui.png b/Resources/img/KS_nav_ui.png new file mode 100644 index 0000000000000000000000000000000000000000..28976c8680a455227bab8102bcc624492c0db793 GIT binary patch literal 1158 zcmV;11bO?3P)H=jVHj@bY}4s!uFxD4<6p{oHM@jocDX*=l#BK5|_($=pZ)k&;e~B;vwQ8;vwQ8 z;=h|z><=XpiDGzo_<>9&)9>u;NT_i60-pV`zWUz36M*L0+S(c~EiJu)zTID8l=L6e-EoU^&P$@$6wYGkES=}uc)+h@64z7RB3@zE6B z-Q5oo5)!Tup@M>fGTh50MQ}JAMM+6XkHsXXPN%y*KR?g2)Nu`7enz;6jEp=6lMIAS zPfu&b4zjqosNLS)ma`i7y)-9=^s<=VDZ4aB%SI#KZ*0GC9>srSh7GwwJ&p z0^vwh(Nhlv(xDE`YImt;7Ap42%F5QNs;U^M zLsVB+*GsCTR1{}tXXjB7r$9<0R7p=Y5ui{g%qTt!X=!OmEQy;*RqE^OtyF)2kAR6{ zyuZKyEkI0<_!;9XU`S6-zsS_%z$cP3w|ZFJ9{(M>z&A=@5z55zJnvvhoNsP!KAV-5 z)yi>Pl+kFsRa{*BkR-0Dsp)h^M#f!~a&EUB5JeGG<@Vg%oP;IuXsiJ5U}cv`M6_D% zecXFS+Ky_d&(6-y6C;O6>XT3v8B0}(^HdL%cbe{_fXr+*$BP|gZEYgoREKCg5T#vs5pW8K2*R-n z6|Yg?6)lVX@!AVhx_f{xzPD|i1`0b{FeX& Y0Ca~^4o{F=hX4Qo07*qoM6N<$f>;VBfdBvi literal 0 HcmV?d00001 diff --git a/Resources/img/KS_nav_views.png b/Resources/img/KS_nav_views.png new file mode 100644 index 0000000000000000000000000000000000000000..885abd90062eaeb06103194926db96dc27e99b04 GIT binary patch literal 1074 zcmV-21kL-2P)Y<8Q>Y< zm)lr5gVbs@J2f@+h~u~#p63~g{bKwVucOiEF?~uOwWa#{dh5*0Oo;l-X7h>PJa2zt zWloR_1OiXW%gdjMprj%NN&2L|?d@$R-uD`^p#)X9&CSgcxi8(@+lveg47e5-7kzZU zva%8!92{H<27|oc@6Sh9fl?f2L!ppP?n~$9=6;Wjjm?aVjF5FzHk<9o`1trcyWQ@N zL?W!kVrj$V=CO)%LqkK=7@|oD#}jQPlPSNmvy-o^tSqGawzjrgXpWkin&Pdktv!H$ zke8QdB>F5bFWApWVN)kJQulLTwGk(+}s?y2jvbxmqKwYIDZo=E9Dkn zSXhXV)5k{?sgoiKMHq(RVOa)3G>D=vYA_gd7^5M&i0?y`BGBrT18-_-nocqz6j-fR zGt08a;v6QCJvusS$ zDca0Jc2WV{1^Fc2Amqu4<8WA&Mx)_z%}h*8e9`Omg;iBmHx3RCjzS}VQ^@7y09Sm= z2lpc`muueV^R06m1NgbAc?b_m`FdwP22(++rUZmwr` zc6KuDfFneDp}wabaDnUlDc?D}y1GoYwY8kM#Un}jtALQkaT5IQHms{dYP)|K6HXX- zM@PqtWC{u7DKYJKyVsNi9z|B?aXOt|N}OnU<3Yy;oM3T@^(ovG!i_?B5+650SSk?Wj}zo*GCYLU zYPIVqq(3La`DB25rl+Szq2EI&v(xqW_dl(xtE=wq?R^F61mmltv#zmfyGEn&y2s 0) { - return; - } - var url = 'http://'+ Ti.App.Properties.getString('action_domain', MarchHare.settings.action_domain.default_value)+ diff --git a/Resources/march-hare/march-hare.js b/Resources/march-hare/march-hare.js index 1cec7e1..ae05bf1 100644 --- a/Resources/march-hare/march-hare.js +++ b/Resources/march-hare/march-hare.js @@ -37,25 +37,28 @@ var MarchHare = { MarchHare.xhrReleaseSemaphore(); }); - MarchHare.xhr.setOnload(function() { - if (typeof parameters.file != 'undefined') { - var f = Titanium.Filesystem.getFile( - Titanium.Filesystem.applicationDataDirectory, - parameters.file); + // We use setOnreadystatechange instead of onLoad cause it does not fire + // sometimes: http://bit.ly/bArcbC + MarchHare.xhr.setOnreadystatechange(function() { + if (MarchHare.xhr.readyState != 4) { return; } + if (typeof parameters.file != 'undefined') { + var f = Titanium.Filesystem.getFile( + Titanium.Filesystem.applicationDataDirectory, + parameters.file); - if (Titanium.Platform.name == 'android') { - f.write(this.responseData); - } + if (Titanium.Platform.name == 'android') { + f.write(this.responseData); + } - // If we are downloading a file we will not recieve responseText so - // instead we will pass on the url of the download and the local file - // where it is saved - parameters.onload({file: f.resolve(), url: parameters.url}); - } else { - parameters.onload(this.responseText); - } - MarchHare.xhrReleaseSemaphore(); - }); + // If we are downloading a file we will not recieve responseText so + // instead we will pass on the url of the download and the local file + // where it is saved + parameters.onload({file: f.resolve(), url: parameters.url}); + } else { + parameters.onload(this.responseText); + } + MarchHare.xhrReleaseSemaphore(); + }); if (Titanium.Platform.name != 'android' && (typeof parameters.file != 'undefined')) { diff --git a/Resources/windows/Map.js b/Resources/windows/Map.js index 7431e75..c8ad8c5 100644 --- a/Resources/windows/Map.js +++ b/Resources/windows/Map.js @@ -32,7 +32,7 @@ settings.zoom = Ti.App.Properties.getInt('zoom', MarchHare.settings.zoom.default_value); settings.action_domain = Ti.App.Properties.getString('action_domain', MarchHare.settings.action_domain.default_value); settings.poll = Ti.App.Properties.getString('poll', MarchHare.settings.poll.default_value); - Ti.API.debug('load event for mapview caught, sending settings'); + Ti.API.log('load event for mapview caught, sending settings'); Ti.App.fireEvent('mapWindowLoaded', settings); }); diff --git a/Resources/windows/Reports.js b/Resources/windows/Reports.js index 097b0ca..ff07956 100644 --- a/Resources/windows/Reports.js +++ b/Resources/windows/Reports.js @@ -1,3 +1,8 @@ +/* + - Applying filters to the reports listing is not working + +*/ + (function () { MarchHare.ui.createReportsView = function() { var data = []; @@ -8,8 +13,9 @@ for (i in incidents) { data[i] = Ti.UI.createTableViewRow({ hasChild: true, - height: 'auto', - description: incidents[i].incident.incidentdescription, + height: 50, + top: 0, + desc: incidents[i].incident.incidentdescription, lat: incidents[i].incident.locationlatitude, lon: incidents[i].incident.locationlongitude, date: incidents[i].incident.incidentdate, @@ -18,21 +24,77 @@ ended: incidents[i].incident, backgroundColor: ((incidents[i].incident.incidentread) ? '#000000' : '#404040') }); + data[i].addEventListener('click', function(e) { e.rowData.backgroundColor = '#000000'; + MarchHare.database.setIncidentRead(e.rowData.id, true); + var infowin = Titanium.UI.createWindow({ + title: e.rowData.title, + }); + var view = Ti.UI.createView({ + layout:'vertical', + }); + + e.row.backgroundColor = '#000000'; + + // TODO: add the location name + //view.add( + infowin.add( + Ti.UI.createLabel({ + text: 'Reported at: '+e.rowData.date, + color: '#FFF', top: 20, height: 'auto', + left: 0, + })); + + // From: http://bit.ly/GMVY7v + infowin.add( + Ti.UI.createLabel({ + text: e.rowData.desc, + color: '#FFF', top: 50, height: 'auto', + left: 0, + })); + + var closeButton = Ti.UI.createButton({ + title: 'close', height: 30, bottom: 10 + }); + + closeButton.addEventListener('click', function() { + infowin.close(); + }); + + infowin.add(view); + infowin.add( closeButton ); + infowin.open({ modal: true }); }); + data[i].addEventListener('longpress', function(e) { + // close this window and center the map on the clicked incident + Ti.API.log('reports longclick handler'); + Ti.App.fireEvent('gotoLocation', { + lat: e.rowData.lat, + lon: e.rowData.lon + }); + + // On Android we close the window + // On iOS we change the tabGroup + if (Ti.Platform.osname == 'android') { + win.close(); + } else { + tabGroup.setActiveTab(mapTab); + } + }); + data[i].add(Ti.UI.createLabel({ text: incidents[i].incident.incidenttitle, - left:0 + top: -30, left:0, color: '#FFF' })); // TODO: It's possible that there are empty strings in incidents[i].icon // this is probably a bug in MarchHare.database.getIncidentsJSON or else // where that needs to get fixed. - var filere = /^file:\/\/\//; - var file; + var filere = /^file:\/\/\/|^\//; for (j in incidents[i].icon) { + var file; if (!incidents[i].icon[j].length) { continue; } // If it is a file make sure it exists @@ -46,75 +108,37 @@ // web urls as arguments for backgroundImage :( continue; } - data[i].add(Titanium.UI.createImageView({ - backgroundImage: incidents[i].icon[j], - top: 40, width: 16, height: 16, left: 20*j + image: file, + top: 30, width: 16, height: 16, left: 20*j })); } - //break; } if (!incidents.length) { data.push( Ti.UI.createTableViewRow({title: 'No reports have been added'})); } + tableView = Titanium.UI.createTableView({data: data}); return tableView; } MarchHare.ui.createReportsWindow = function() { + // We do not use modal windows on iOS + var useModal = (Ti.Platform.osname == 'android') ? true : false; var win = Ti.UI.createWindow({ backgroundColor: '#000', title: 'Reports', - modal: true + modal: useModal }); var view = MarchHare.ui.createReportsView(); - view.addEventListener('click', function(e) { - var infowin = Titanium.UI.createWindow({ - modal:true, - title:e.rowData.title - }); - var view = Ti.UI.createView({ - layout:'vertical', - backgroundColor: 'black', - color: 'white' - }); - - MarchHare.database.setIncidentRead(e.rowData.id, true); - e.row.backgroundColor = '#000000'; - - // TODO: add the location name - view.add( - Ti.UI.createLabel({ - text: 'Reported at: '+e.rowData.date, - left: 0 - })); - // From: http://bit.ly/GMVY7v - view.add( - Ti.UI.createLabel({ - text: e.rowData.description, - left: 0 - })); - - infowin.add(view); - infowin.open(); - }); - - view.addEventListener('longclick', function(e) { - // close this window and center the map on the clicked incident - Ti.App.fireEvent('gotoLocation', { - lat: e.rowData.lat, - lon: e.rowData.lon - }); - win.close(); - }); - win.add(view); - return win; + win.add(view); + return win; } - Ti.API.debug('Reports.js loaded'); + Ti.API.log('Reports.js loaded'); })(); diff --git a/Resources/windows/Settings.js b/Resources/windows/Settings.js index 5bcc2e6..96acbb5 100644 --- a/Resources/windows/Settings.js +++ b/Resources/windows/Settings.js @@ -3,12 +3,14 @@ // seem to be a way to create dynamic preference lists // // The example used to create this was pulled from: http://bit.ly/KbLUA7 - + + // We do not use modal windows on iOS + var useModal = (Ti.Platform.osname == 'android') ? true : false; MarchHare.ui.createSettingsWindow = function() { var win = Ti.UI.createWindow({ - backgroundColor: '#000', + //backgroundColor: '#000', title: 'Settings', - modal: true + modal: useModal }); var sections = new Array; @@ -17,14 +19,15 @@ headerTitle: "Application Settings" }); - var domainRow = Ti.UI.createTableViewRow(); + var domainRow = Ti.UI.createTableViewRow({ height: 50 }); // TODO: this should actually all be wrapped in a table with each setting // that is not a checkbox diverted to its own modal window var domainLabel = Ti.UI.createLabel({ text: 'Action Domain: ', top: 0, left: 0, - color: '#fff' }); + //color: '#fff' + }); domainRow.add(domainLabel); @@ -32,8 +35,7 @@ // want to use. We will have to change this dependent on a new property // in the MarchHare.settings list var domainField = Ti.UI.createTextField( { - //top:20, left:0, width: 200, - left:0, width: 200, top: 20, + left:0, width: 200, top: 30, hintText: Ti.App.Properties.getString('action_domain', MarchHare.settings.action_domain.default_value), autoCorrect: false, @@ -74,7 +76,8 @@ var pollLabel = Ti.UI.createLabel({ text: 'Poll Frequency in Seconds:', top: 10, left: 0, - color: '#fff' }); + //color: '#fff' + }); pollRow.add(pollLabel); var pollField = Ti.UI.createTextField( { @@ -112,7 +115,8 @@ var GPSLabel = Ti.UI.createLabel({ text: 'Update map w/ GPS: ', top: 0, left: 0, - color: '#fff' }); + //color: '#fff' + }); GPSRow.add(GPSLabel); var GPSField = Ti.UI.createSwitch( { @@ -144,7 +148,8 @@ var VibLabel = Ti.UI.createLabel({ text: 'Vibrate on new report: ', top: 0, left: 0, - color: '#fff' }); + //color: '#fff' + }); VibRow.add(VibLabel); var VibField = Ti.UI.createSwitch( { @@ -174,6 +179,7 @@ }); // Get all of the categories + var categoryFiltersUpdated = false; var categories = MarchHare.database.getCategoriesJSON(); categories = JSON.parse(categories); for (i in categories) { @@ -189,7 +195,8 @@ var categoryLabel = Ti.UI.createLabel({ text: categories[i].title+': ', top: 0, left: 0, - color: '#fff' }); + //color: '#fff' + }); categoryRow.add(categoryLabel); var categorySwitch = Ti.UI.createSwitch({ @@ -206,6 +213,7 @@ categorySwitch. addEventListener("change", function(e) { MarchHare.database.setCategoryFilter(e.source.category_id, e.value); + categoryFiltersUpdated = true; }); categoryRow.add(categorySwitch); @@ -219,12 +227,23 @@ win.add(tableView); + // With Android modal windows we close the settings window, but with iOS we blur the window win.addEventListener('close', function() { - Ti.App.fireEvent('filterReports'); + if (categoryFiltersUpdated) { + categoryFiltersUpdated = false; + Ti.App.fireEvent('filterReports'); + } + }); + + win.addEventListener('blur', function() { + if (categoryFiltersUpdated) { + categoryFiltersUpdated = false; + Ti.App.fireEvent('filterReports'); + } }); return win; } - Ti.API.debug('Settings.js loaded'); + Ti.API.log('Settings.js loaded'); })(); diff --git a/tiapp.xml b/tiapp.xml index 7d21aa9..09e8652 100644 --- a/tiapp.xml +++ b/tiapp.xml @@ -8,7 +8,7 @@ true false - 2.0.1.GA2 + 1.8.2 org.marchhare.natog82012 NATO-G8 2012 Beta RC1 From 6075db2b3e81d37ede9a25c0feddb2982bb9e6c9 Mon Sep 17 00:00:00 2001 From: "Mr. Evoltech" Date: Tue, 8 May 2012 17:54:39 -0700 Subject: [PATCH 3/6] Merge of iOS port and touchups to co-exist with android specific stuff --- Resources/march-hare/march-hare.js | 4 +- Resources/windows/Reports.js | 71 +++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/Resources/march-hare/march-hare.js b/Resources/march-hare/march-hare.js index ae05bf1..8ae4a58 100644 --- a/Resources/march-hare/march-hare.js +++ b/Resources/march-hare/march-hare.js @@ -1,6 +1,8 @@ // TODO: i18n inegration var MarchHare = { - ui: {}, + ui: { + Android: (Ti.Platform.osname == 'android') ? true : false, + }, database: {}, xhr: Ti.Network.createHTTPClient(), xhrGetSemaphore: function(message) { diff --git a/Resources/windows/Reports.js b/Resources/windows/Reports.js index ff07956..d1c5fdd 100644 --- a/Resources/windows/Reports.js +++ b/Resources/windows/Reports.js @@ -15,6 +15,8 @@ hasChild: true, height: 50, top: 0, + // title is a keyword that we dont want to use here + tit: incidents[i].incident.incidenttitle, desc: incidents[i].incident.incidentdescription, lat: incidents[i].incident.locationlatitude, lon: incidents[i].incident.locationlongitude, @@ -30,27 +32,36 @@ MarchHare.database.setIncidentRead(e.rowData.id, true); var infowin = Titanium.UI.createWindow({ title: e.rowData.title, + backgroundColor: '#000' }); - var view = Ti.UI.createView({ - layout:'vertical', - }); + var scrollview = Ti.UI.createScrollView({ layout: 'vertical' }); + //var view = Ti.UI.createView({ layout:'vertical', }); e.row.backgroundColor = '#000000'; // TODO: add the location name //view.add( - infowin.add( + //infowin.add( + scrollview.add( + Ti.UI.createLabel({ + text: 'Title: '+e.rowData.tit, + color: '#FFF', /*top: 20,*/ height: 'auto', + left: 0, + })); + + scrollview.add( Ti.UI.createLabel({ text: 'Reported at: '+e.rowData.date, - color: '#FFF', top: 20, height: 'auto', + color: '#FFF', /*top: 30,*/ height: 'auto', left: 0, })); // From: http://bit.ly/GMVY7v - infowin.add( + //infowin.add( + scrollview.add( Ti.UI.createLabel({ text: e.rowData.desc, - color: '#FFF', top: 50, height: 'auto', + color: '#FFF', /*top: 70,*/ height: 'auto', left: 0, })); @@ -61,32 +72,38 @@ closeButton.addEventListener('click', function() { infowin.close(); }); + scrollview.add(closeButton); - infowin.add(view); - infowin.add( closeButton ); + //infowin.add(view); + infowin.add(scrollview); + //infowin.add( closeButton ); infowin.open({ modal: true }); }); - data[i].addEventListener('longpress', function(e) { - // close this window and center the map on the clicked incident - Ti.API.log('reports longclick handler'); + // It does not seem like android will fire longpresses, but I am not + // sure that iOS doesn't fire both + if (MarchHare.ui.Android) { + data[i].addEventListener('longclick', fireGotoLocation); + } else { + data[i].addEventListener('longpress', fireGotoLocation); + } + + function fireGotoLocation(e) { + Ti.API.log('longpress or longclick detected gotoLocation being fired'); Ti.App.fireEvent('gotoLocation', { lat: e.rowData.lat, lon: e.rowData.lon }); + } - // On Android we close the window - // On iOS we change the tabGroup - if (Ti.Platform.osname == 'android') { - win.close(); - } else { - tabGroup.setActiveTab(mapTab); - } - }); - + // TODO: we should move all formatting stuff like this to jss files + var top = -2; + if (!MarchHare.ui.Android) { + top = -30; + } data[i].add(Ti.UI.createLabel({ text: incidents[i].incident.incidenttitle, - top: -30, left:0, color: '#FFF' + top: top, left:0, color: '#FFF' })); // TODO: It's possible that there are empty strings in incidents[i].icon @@ -133,8 +150,18 @@ title: 'Reports', modal: useModal }); + var view = MarchHare.ui.createReportsView(); + // On Android we close the window, iOS we switch tabs + Ti.App.addEventListener('gotoLocation', function(e){ + if (MarchHare.ui.Android) { + win.close(); + } else { + tabGroup.setActiveTab(mapTab); + } + }); + win.add(view); return win; } From 2c5a987236541ec5cc043beeb60216f29e18c98d Mon Sep 17 00:00:00 2001 From: "Mr. Evoltech" Date: Wed, 9 May 2012 16:09:16 -0700 Subject: [PATCH 4/6] provides a solution for but not a fix for issue #51 --- Resources/app.js | 1 + Resources/march-hare/database.js | 77 ++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Resources/app.js b/Resources/app.js index 5a2c472..0fd7090 100644 --- a/Resources/app.js +++ b/Resources/app.js @@ -125,6 +125,7 @@ if (DEV) { // Force a lookup of all categories everytime the application starts MarchHare.database.initializeCategories(); +MarchHare.database.initializeIncidents(); MarchHare.database.initializeMidPoint(); // TODO: in testing I have noticed that this completes before the MapWindow is diff --git a/Resources/march-hare/database.js b/Resources/march-hare/database.js index f2e35bf..c384b8a 100644 --- a/Resources/march-hare/database.js +++ b/Resources/march-hare/database.js @@ -552,11 +552,10 @@ } MarchHare.database.initializeIncidents = function() { - MarchHare.database.flushIncidents(); var url = 'http://'+ Ti.App.Properties.getString('action_domain', MarchHare.settings.action_domain.default_value)+ - '/api?task=decayimage'; + '/api?task=decayimage&limit=100'; // TODO: start an indicator var t = setInterval(function() { @@ -570,7 +569,7 @@ MarchHare.xhrProcess({ url: url, onload: function(response) { - handleServerResponse(response); + MarchHare.database.handleServerResponseIncidents(response); Ti.App.fireEvent('incidentsDownloaded'); } }); @@ -582,36 +581,66 @@ MarchHare.database.handleServerResponseIncidents = function(response) { var jNewIncidents = JSON.parse(response); var newIncidents = false; + var incidentids = []; + var error = false; if ( typeof jNewIncidents == 'undefined' || typeof jNewIncidents.payload == 'undefined' || typeof jNewIncidents.payload.incidents == 'undefined' || - !(jNewIncidents.payload.incidents instanceof Array) ){ - Ti.API.error('initializeIncidents: recieved invalid json from the server: '+ - JSON.stringify(jNewIncidents)); - return false; - } + !(jNewIncidents.payload.incidents instanceof Array) + ) { - for ( var i in jNewIncidents.payload.incidents) { - newIncidents = true; - var incident = { - incident: { - incidentid: jNewIncidents.payload.incidents[i].incident.incidentid, - incidenttitle: jNewIncidents.payload.incidents[i].incident.incidenttitle, - incidentdescription: jNewIncidents.payload.incidents[i].incident.incidentdescription, - incidentdate: jNewIncidents.payload.incidents[i].incident.incidentdate, - incidentlatitude: jNewIncidents.payload.incidents[i].incident.locationlatitude, - incidentlongitude: jNewIncidents.payload.incidents[i].incident.locationlongitude, - }, - categories: jNewIncidents.payload.incidents[i].categories - }; + // It may just be the case that we have not recieved any data back + // from our request + if ( + typeof jNewIncidents.error.code != 'undefined' && + (jNewIncidents.error.code == "007") && + typeof jNewIncidents.error.message != 'undefined' + ) { + } + else { + Ti.API.error('MarchHare.database.handleServerResponseIncidents: recieved invalid json from the server: '+ + JSON.stringify(jNewIncidents)); + error = true; + } + } else { - MarchHare.database.setIncident(incident); + // TODO: this finishes before the settings are sent to the map, so it does + // not actually load until after the next poll + for ( var i in jNewIncidents.payload.incidents) { + incidentids.push(parseInt(jNewIncidents.payload.incidents[i].incident.incidentid)); + var incident = { + incident: { + incidentid: jNewIncidents.payload.incidents[i].incident.incidentid, + incidenttitle: jNewIncidents.payload.incidents[i].incident.incidenttitle, + incidentdescription: jNewIncidents.payload.incidents[i].incident.incidentdescription, + incidentdate: jNewIncidents.payload.incidents[i].incident.incidentdate, + incidentlatitude: jNewIncidents.payload.incidents[i].incident.locationlatitude, + incidentlongitude: jNewIncidents.payload.incidents[i].incident.locationlongitude, + incidenthasended: jNewIncidents.payload.incidents[i].incident.incidenthasended, + }, + categories: jNewIncidents.payload.incidents[i].categories + }; + + if (MarchHare.database.getIncidentJSON(incident)) { + MarchHare.database.updateIncident(incident); + } else { + MarchHare.database.setIncident(incident); + } + } } - if (!newIncidents) { - Ti.API.debug('nitializeIncidents: did not recieve any reports'); + // Delete all old incidents + var rows = MarchHare.database.getIncidents(); + while (rows.isValidRow()) { + var id = rows.fieldByName('id'); + rows.next(); + if (incidentids.indexOf(id) != -1) { continue; } + var query = 'DELETE FROM incident_categories WHERE incident_id='+id; + db.execute(query); + query = 'DELETE FROM incidents WHERE id='+id; + db.execute(query); } } From fce18f6b3055967cf58dd7c7230bef5a590dd179 Mon Sep 17 00:00:00 2001 From: "Mr. Evoltech" Date: Wed, 9 May 2012 16:12:00 -0700 Subject: [PATCH 5/6] This fixes a bug with the pollForReports loop not detecting newIncidents --- Resources/app.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Resources/app.js b/Resources/app.js index 0fd7090..28675b9 100644 --- a/Resources/app.js +++ b/Resources/app.js @@ -284,7 +284,7 @@ function pollForReports() { var url = 'http://'+ Ti.App.Properties.getString('action_domain', MarchHare.settings.action_domain.default_value)+ - '/api/?task=decayimage&by=sincedate&date='+lastpoll; + '/api/?task=decayimage&by=sincedate&limit=100&date='+lastpoll; // TODO: start an indicator var t = setInterval(function() { @@ -361,12 +361,13 @@ function handleServerResponse(response) { // if we already found a newIncident we dont have to keep checking if (!newIncidents) { - // Loop across the assigned categories to see if it is one we are i + // Loop across the assigned categories to see if it is one we are // interested in for (j in jNewIncidents.payload.incidents[i].categories) { - if (jNewIncidents.payload.incidents[i].categories[j].category.id in categories) { + if ( categories.indexOf(parseInt(jNewIncidents.payload.incidents[i].categories[j].category.id)) != -1) { newIncidents = true; - } + break; + } } } } From e5a18c696e52dfe01f8cad11e9751863cd8273cd Mon Sep 17 00:00:00 2001 From: "Mr. Evoltech" Date: Wed, 9 May 2012 16:21:25 -0700 Subject: [PATCH 6/6] Ti.API.log is not supported in webView --- Resources/js/reports.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/js/reports.js b/Resources/js/reports.js index 9b2ccb9..e14de3b 100644 --- a/Resources/js/reports.js +++ b/Resources/js/reports.js @@ -31,7 +31,7 @@ Ti.App.addEventListener('mapWindowLoaded', init); function init(settings) { - Ti.API.log('reports.js init called with settings: '+JSON.stringify(settings)); + Ti.API.debug('reports.js init called with settings: '+JSON.stringify(settings)); updateSettings(settings); $(document).ready(function() { map = createMap('map', latitude, longitude, defaultZoom); @@ -79,13 +79,13 @@ (typeof(location.lat) === 'undefined') || (typeof(location.lon) === 'undefined') ) { - Ti.API.log('handleUpdateGeolocation did not recieve location info'); + Ti.API.error('handleUpdateGeolocation did not recieve location info'); return; } // check to see if it is different then the values we already have if ( (latitude != location.lat) || (longitude != location.lon) ) { - Ti.API.log('handleUpdateGeolocation updating the "Current Location" layer'); + Ti.API.info('handleUpdateGeolocation updating the "Current Location" layer'); var oldLayer = map.getLayersByName('Current Location'); for (var i = 0; i < oldLayer.length; i++) { @@ -139,7 +139,7 @@ var lat = latitude; var lon = longitude; - Ti.API.log('js/reports.js mapSetCenter this: '+ JSON.stringify(settings)); + Ti.API.debug('js/reports.js mapSetCenter this: '+ JSON.stringify(settings)); // Optionally accept bound parameters if ( typeof settings !== 'undefined' &&