├── LICENSE ├── README.md ├── elements ├── AddressInput.py ├── AdjustDate.py ├── AppendtoVariable.py ├── Changetimezone.py ├── ConverttoNumber.py ├── ConverttoText.py ├── Count.py ├── Date.py ├── DateInput.py ├── ElementBase.py ├── ElementParameter.py ├── ElementValue.py ├── Else.py ├── EndFor.py ├── EndForEach.py ├── EndIf.py ├── For.py ├── ForEach.py ├── GenerateHashOfString.py ├── GetAddressfromLocation.py ├── GetBatteryDetails.py ├── GetClipboardImage.py ├── GetClipboardText.py ├── GetCurrentLocation.py ├── GetImagesfromAppextension.py ├── GetLocationfromAddress.py ├── GetName.py ├── GetScreenBrightness.py ├── GetURLContents.py ├── GetVariable.py ├── If.py ├── ListTest.py ├── Nothing.py ├── NumberInput.py ├── OpenLocationinAppleMaps.py ├── OpenLocationinGoogleMaps.py ├── OpenURLin.py ├── PickImagefromPhotos.py ├── PlayAudio.py ├── Print.py ├── RecordAudio.py ├── SaveImagetoCameraRoll.py ├── SetClipboardImage.py ├── SetClipboardText.py ├── SetName.py ├── SetScreenBrightness.py ├── SetVariable.py ├── SetVolume.py ├── ShowAlert.py ├── ShowlocationonMap.py ├── Sleep.py ├── SpeakText.py ├── TakePhoto.py ├── Template.py ├── TextInput.py ├── TexttoURL.py ├── VibrateDevice.py └── __init__.py ├── istaflow.py ├── managers ├── ElementManager.py ├── FlowManager.py ├── HomeScreenManager.py ├── SettingsManager.py ├── ThemeManager.py ├── WebClipper.py └── __init__.py └── views ├── AssetPickerView.py ├── ElementCreationView.py ├── ElementListView.py ├── ElementManagementView.py ├── ElementParameterDictionaryInputView.py ├── ElementRuntimeView.py ├── FlowCreationView.py ├── FlowsView.py ├── MapView.py ├── ToastView.py └── __init__.py /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Shaun Hevey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #istaflow 2 | Istaflow is automation app built for pythonista. This has been inspired by workflow for iOS you can find it here [Workflow](https://workflow.is) 3 | 4 | You create flows to run flows. Each flow is made up of a series of elements. These elements have a single purpose and are reusable across flows. 5 | 6 | Istaflow currently can run basic flows currently with simple validation for an input to each element. 7 | Istaflow it is in active development but should still be classed as beta as there will be plenty of bugs and features still to add. 8 | 9 | This has been built with pythonista 3 and has only had slight testing in 2. 10 | NOTE: Now that Pythonista 3 has been released I wont be supporting Pythonista 2 so all work arounds that have been included will eventually be removed. 11 | 12 | -------------------------------------------------------------------------------- /elements/AddressInput.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import dialogs 6 | 7 | class AddressInput(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return None 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'address' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'Manually enter an address' 41 | 42 | def get_title(self): 43 | return 'Address Input' 44 | 45 | def get_icon(self): 46 | return 'iob:map_32' 47 | 48 | def get_category(self): 49 | return 'Location' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input=''): 55 | formDict = [{'type':'text','title':'Title','key':'title'}, 56 | {'type':'text', 'title':'Street', 'autocorrection':False}, 57 | {'type':'text', 'title':'City', 'autocorrection':False}, 58 | {'type':'text', 'title':'Country', 'autocorrection':False}, 59 | {'type':'text', 'title':'Zip Postcode','key':'ZIP', 'autocorrection':False}] 60 | address = dialogs.form_dialog(title='Address Input', fields=formDict) 61 | ev = ElementValue(type = self.get_output_type(), value = address) 62 | self.status = 'complete' 63 | return ev 64 | 65 | if __name__ == '__main__': 66 | AddressInput().run() 67 | 68 | -------------------------------------------------------------------------------- /elements/AdjustDate.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | import datetime 7 | 8 | class AdjustDate(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = [] 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return False 18 | 19 | def setup_params(self): 20 | self.params.append(ElementParameter(name='timeadjusttype',displayName='Adjust Type',display=True,type='list',value='Seconds',allowedValues=['Microseconds', 'Milliseconds','Seconds','Minutes','Hours','Days','Weeks'],multipleAllowed=False,isVariableAllowed=False)) 21 | self.params.append(ElementParameter(name='amount',displayName='Amount',display=True,type='int',value=0)) 22 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 23 | 24 | def get_status(self): 25 | return self.status 26 | 27 | def get_input_type(self): 28 | return 'datetime' 29 | 30 | def get_output(self): 31 | return self.output 32 | 33 | def get_output_type(self): 34 | return 'datetime' 35 | 36 | def get_params(self): 37 | return self.params 38 | 39 | def set_params(self, params = None): 40 | self.params = params or [] 41 | 42 | def get_description(self): 43 | return 'Add some time to the date' 44 | 45 | def get_title(self): 46 | return 'Adjust Date' 47 | 48 | def get_icon(self): 49 | return 'iob:clock_32' 50 | 51 | def get_category(self): 52 | return 'Date' 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self, input=''): 58 | amount = self.get_param_by_name('amount') 59 | option = self.get_param_by_name('timeadjusttype') 60 | td = None 61 | if option.value == 'Microseconds': 62 | td = datetime.timedelta(microseconds=amount.value) 63 | elif option.value == 'Milliseconds': 64 | td = datetime.timedelta(milliseconds = amount.value) 65 | elif option.value == 'Seconds': 66 | td = datetime.timedelta(seconds=amount.value) 67 | elif option.value == 'Minutes': 68 | td = datetime.timedelta(minutes=amount.value) 69 | elif option.value == 'Hours': 70 | td = datetime.timedelta(hours=amount.value) 71 | elif option.value == 'Days': 72 | td = datetime.timedelta(days=amount.value) 73 | elif option.value == 'Weeks': 74 | td = datetime.timedelta(weeks=amount.value) 75 | if td: 76 | input.value = input.value + td 77 | self.status = 'Complete' 78 | return input 79 | -------------------------------------------------------------------------------- /elements/AppendtoVariable.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import console 6 | import copy 7 | from objc_util import * 8 | 9 | class AppendtoVariable(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = [] 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return True 19 | 20 | def setup_params(self): 21 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 22 | self.params.append(ElementParameter(name='VariableName',displayName='Variable Name',display=True,type='string')) 23 | 24 | def get_status(self): 25 | return self.status 26 | 27 | def get_input_type(self): 28 | return '*' 29 | 30 | def get_output(self): 31 | return self.output 32 | 33 | def get_output_type(self): 34 | return None 35 | 36 | def get_params(self): 37 | return self.params 38 | 39 | def set_params(self, params = None): 40 | self.params = params or [] 41 | 42 | def get_description(self): 43 | return 'Appends input to a set variable' 44 | 45 | def get_title(self): 46 | return 'Append to Variable' 47 | 48 | def get_icon(self): 49 | return 'iob:gear_a_32' 50 | 51 | def get_category(self): 52 | return 'Utility' 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self, input=''): 58 | np = self.get_param_by_name('VariableName') 59 | name = np.value or console.input_alert('Please enter Variable name') 60 | rv = self.get_param_by_name('fm:runtime_variables') 61 | if not name in rv.value: 62 | rv.value[name] = None 63 | if rv.value[name] == None: 64 | rv.value[name] = input.copyMe() 65 | rv.value[name].value = [] 66 | rv.value[name].value.append(input.copyValue()) 67 | #if not input.objcCopy: 68 | # rv.value[name] = copy.deepcopy(input) 69 | #else: 70 | # ev = ElementValue(input.type, input.value.copy(), input.isList, ) 71 | # rv.value[name] = ev 72 | else: 73 | if input.type == rv.value[name].type: 74 | if not isinstance(rv.value[name].value,list): 75 | #t = copy.deepcopy(rv.value[name].value) 76 | t = rv.value[name].copyValue() 77 | rv.value[name].value = [] 78 | rv.value[name].value.append(t) 79 | 80 | if isinstance(input,list): 81 | 82 | for i in input.copyValue(): 83 | rv.value[name].value.append(i) 84 | else: 85 | rv.value[name].value.append(input.copyValue()) 86 | else: 87 | console.alert('Error','Incorrect type to append to variable',button1='Ok',hide_cancel_button=True) 88 | 89 | self.status = 'complete' 90 | 91 | -------------------------------------------------------------------------------- /elements/Changetimezone.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import pytz 6 | 7 | class Changetimezone(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = [] 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | a = pytz.all_timezones_set 20 | tm = [] 21 | for aa in a: 22 | tm.append(aa) 23 | tm.sort() 24 | self.params.append(ElementParameter(name='timezone',displayName='Time Zone',display=True,type='list',value=None,allowedValues=tm,multipleAllowed=False,isVariableAllowed=False)) 25 | 26 | def get_status(self): 27 | return self.status 28 | 29 | def get_input_type(self): 30 | return 'datetime' 31 | 32 | def get_output(self): 33 | return self.output 34 | 35 | def get_output_type(self): 36 | return 'datetime' 37 | 38 | def get_params(self): 39 | return self.params 40 | 41 | def set_params(self, params = None): 42 | self.params = params or [] 43 | 44 | def get_description(self): 45 | return 'Changes the timezone of the passed datetime object' 46 | 47 | def get_title(self): 48 | return 'Change timezone' 49 | 50 | def get_icon(self): 51 | return 'iob:earth_32' 52 | 53 | def get_category(self): 54 | return 'Date' 55 | 56 | def get_type(self): 57 | return self.type 58 | 59 | def run(self, input=''): 60 | tz = self.get_param_by_name('timezone') 61 | if not tz.value == None: 62 | timezonetouse = pytz.timezone(tz.value) 63 | input.value = input.value.astimezone(timezonetouse) 64 | self.status = 'complete' 65 | return input 66 | -------------------------------------------------------------------------------- /elements/ConverttoNumber.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class ConverttoNumber(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return False 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return 'number' 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'Tries to convert the input to a number' 40 | 41 | def get_title(self): 42 | return 'Convert to Number' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_cog_32' 46 | 47 | def get_category(self): 48 | return 'Number' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | if not input.value == None and input.value.isdigit(): 55 | self.output = float(str(input.value)) 56 | self.status = 'complete' 57 | return ElementValue(type = self.get_output_type(), value = self.output) 58 | else: 59 | self.status = 'error' 60 | -------------------------------------------------------------------------------- /elements/ConverttoText.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class ConverttoText(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return False 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return 'text' 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'Tries to convert input to a string' 40 | 41 | def get_title(self): 42 | return 'Convert to Text' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_cog_32' 46 | 47 | def get_category(self): 48 | return 'Text' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | self.output = str(input.value) 55 | self.status = 'complete' 56 | return ElementValue(type = self.get_output_type(), value = self.output) 57 | 58 | -------------------------------------------------------------------------------- /elements/Count.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class Count(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return True 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return 'number' 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'Get the count of an object or list' 40 | 41 | def get_title(self): 42 | return 'Count' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_cog_outline_32' 46 | 47 | def get_category(self): 48 | return 'Utility' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | self.status = 'complete' 55 | return ElementValue(type=self.get_output_type(), value=len(input.value)) 56 | -------------------------------------------------------------------------------- /elements/Date.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import datetime 6 | from dateutil.tz import * 7 | 8 | class Date(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = [] 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return False 18 | 19 | def setup_params(self): 20 | self.params.append(ElementParameter(name='useutc',displayName='Return in UTC (otherwise local time)',display=True,type='bool',value=False)) 21 | 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return None 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return 'datetime' 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = None): 39 | self.params = params or [] 40 | 41 | def get_description(self): 42 | return 'Return the current date and time' 43 | 44 | def get_title(self): 45 | return 'Date' 46 | 47 | def get_icon(self): 48 | return 'iob:clock_32' 49 | 50 | def get_category(self): 51 | return 'Date' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | def run(self, input=''): 57 | utcparam = self.get_param_by_name('useutc') 58 | local = tzlocal() 59 | utc = tzutc() 60 | now = datetime.datetime.now() 61 | now = now.replace(tzinfo = local) 62 | if utcparam.value: 63 | now = now.astimezone(utc) 64 | self.status = 'Complete' 65 | return ElementValue(type=self.get_output_type(), value=now) 66 | -------------------------------------------------------------------------------- /elements/DateInput.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | import dialogs 7 | import ui 8 | 9 | class DateInput(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = [] 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return False 19 | 20 | def setup_params(self): 21 | self.params.append(ElementParameter(name='type',displayName='DateTime/Date',display=True,type='list',value='DateTime',allowedValues=['DateTime','Date'],isVariableAllowed=False)) 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return None 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return 'datetime' 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = None): 39 | self.params = params or [] 40 | 41 | def get_description(self): 42 | return 'Date input element' 43 | 44 | def get_title(self): 45 | return 'Date Input' 46 | 47 | def get_icon(self): 48 | return 'iob:clock_32' 49 | 50 | def get_category(self): 51 | return 'Date' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | 57 | def run(self, input=''): 58 | type = self.get_param_by_name('type').value 59 | value = None 60 | if type == 'DateTime': 61 | value = dialogs.datetime_dialog('Date entry') 62 | elif type == 'Date': 63 | value = dialogs.date_dialog('Date entry') 64 | if value == None: 65 | raise KeyboardInterrupt 66 | self.status = 'complete' 67 | return ElementValue(type=self.get_output_type(), value=value) 68 | -------------------------------------------------------------------------------- /elements/ElementBase.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import dialogs 3 | import console 4 | import copy 5 | 6 | class ElementBase (object): 7 | def can_handle_list(self): 8 | raise self.not_implemented() 9 | 10 | def get_status(self): 11 | raise self.not_implemented() 12 | 13 | def get_input(self): 14 | raise self.not_implemented() 15 | 16 | def get_output(self): 17 | raise self.not_implemented() 18 | 19 | def get_input_type(self): 20 | raise self.not_implemented() 21 | 22 | def get_output_type(self): 23 | raise self.not_implemented() 24 | 25 | def get_params(self): 26 | raise self.not_implemented() 27 | 28 | def set_params(self): 29 | raise self.not_implemented() 30 | 31 | def get_description(self): 32 | raise self.not_implemented() 33 | 34 | def get_title(self): 35 | raise self.not_implemented() 36 | 37 | def get_icon(self): 38 | raise self.not_implemented() 39 | 40 | def get_category(self): 41 | raise self.not_implemented() 42 | 43 | def get_type(self): 44 | raise self.not_implemented() 45 | 46 | def run(self): 47 | raise self.not_implemented() 48 | 49 | def get_runtime_variable_for_parameter(self, parameter): 50 | rv = self.get_param_by_name('fm:runtime_variables') 51 | if rv == None: 52 | raise LookupError('Element requires fm:runtime_variables') 53 | 54 | keysavailablestring = '' 55 | for k in rv.value: 56 | keysavailablestring += k + ' ' 57 | keysavailablemessage = 'Keys to choose from are: ' + keysavailablestring 58 | while parameter.variableName == None or parameter.variableName.replace(' ', '') == '': 59 | try: 60 | key = dialogs.list_dialog('Vars',list(rv.value.keys())) 61 | parameter.variableName = key 62 | except : 63 | # if dialogs isnt available then fall back to console input 64 | parameter.variableName = console.input_alert(title='Please enter variable title', message=keysavailablemessage) 65 | if parameter.variableName in rv.value: 66 | parameter.value = copy.deepcopy(rv.value[parameter.variableName].value) 67 | else: 68 | raise KeyError('Parameter ' + parameter.variableName + ' does not exist') 69 | 70 | def get_param_by_name(self, name): 71 | params_by_name = [p for p in self.params if p.name == name] 72 | return params_by_name[-1] if params_by_name else None 73 | 74 | def not_implemented(self): 75 | import inspect 76 | fmt = 'Class {} does not implement {}()' 77 | caller_name = inspect.getouterframes(inspect.currentframe(), 2)[1][3] 78 | return NotImplementedError(fmt.format(self.__class__.__name__, caller_name)) 79 | -------------------------------------------------------------------------------- /elements/ElementParameter.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class ElementParameter (object): 3 | def __init__(self, name, type, displayName='', display=False, value=None, allowedValues=None, multipleAllowed=False, isVariableAllowed = True, askAtRuntime = False): 4 | self.name = name 5 | self.displayName = displayName 6 | self.display = display 7 | self.type = type 8 | self.value = value 9 | self.allowedValues = allowedValues or [] 10 | self.multipleAllowed = multipleAllowed 11 | self.useVariable = False 12 | self.isVariableAllowed = isVariableAllowed 13 | self.variableName = '' 14 | self.askAtRuntime = askAtRuntime 15 | -------------------------------------------------------------------------------- /elements/ElementValue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class ElementValue (object): 3 | def __init__(self, type, value, name='', objcCopy=False): 4 | self.type = type 5 | self.value = value 6 | #self.isList = isinstance(value, list) 7 | self.name = name 8 | self.objcCopy = objcCopy 9 | 10 | @property 11 | def isList(self): 12 | return isinstance(self.value, list) 13 | 14 | def copyMe(self): 15 | if self.objcCopy: 16 | type = self.type 17 | if isinstance(self.value,list): 18 | data = [] 19 | for d in self.value: 20 | data.append(d.copy()) 21 | else: 22 | data = self.value.copy() 23 | value = data 24 | name = self.name 25 | objcCopy = self.objcCopy 26 | ev = ElementValue(type=type, value=value, name=name, objcCopy=self.objcCopy) 27 | return ev 28 | else: 29 | import copy 30 | return copy.deepcopy(self) 31 | def copyValue(self): 32 | if self.objcCopy: 33 | if isinstance(self.value,list): 34 | data = [] 35 | for d in self.value: 36 | data.append(d.copy()) 37 | else: 38 | data = self.value.copy() 39 | return data 40 | else: 41 | import copy 42 | return copy.deepcopy(self.value) 43 | -------------------------------------------------------------------------------- /elements/Else.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class Else(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Else' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return True 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return '*' 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'Else conditional block' 40 | 41 | def get_title(self): 42 | return 'Else' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_drag_32' 46 | 47 | def get_category(self): 48 | return 'Dont Display' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | self.status = 'complete' 55 | return input 56 | -------------------------------------------------------------------------------- /elements/EndFor.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class EndFor(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'EndFor' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return False 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return None 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return None 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'End of For loop' 40 | 41 | def get_title(self): 42 | return 'End For' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_drag_32' 46 | 47 | def get_category(self): 48 | return 'Dont Display' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | self.status = 'complete' 55 | return None 56 | 57 | -------------------------------------------------------------------------------- /elements/EndForEach.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class EndForEach(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'EndForeach' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | pass 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return None 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return None 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'End of Foreach' 40 | 41 | def get_title(self): 42 | return 'End Foreach' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_drag_32' 46 | 47 | def get_category(self): 48 | return 'Dont Display' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | return ElementValue(type='',value='') 55 | -------------------------------------------------------------------------------- /elements/EndIf.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class EndIf(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'EndIf' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return True 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return None 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return None 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'End of the if conditional block' 40 | 41 | def get_title(self): 42 | return 'End If' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_drag_32' 46 | 47 | def get_category(self): 48 | return 'Dont Display' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | self.status = 'complete' 55 | return None 56 | -------------------------------------------------------------------------------- /elements/For.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class For(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = [] 11 | self.type = 'For' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return False 16 | 17 | def setup_params(self): 18 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 19 | self.params.append(ElementParameter(name='forcount',displayName='For Loop Count',display=True,type='int',value=1)) 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return None 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return None 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'For Loop' 41 | 42 | def get_title(self): 43 | return 'For' 44 | 45 | def get_icon(self): 46 | return 'iob:arrow_return_right_32' 47 | 48 | def get_category(self): 49 | return 'Conditional' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input=''): 55 | self.status = 'complete' 56 | return None 57 | 58 | -------------------------------------------------------------------------------- /elements/ForEach.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class ForEach(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Foreach' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return True 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return '*' 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'Pull each element of a list out' 40 | 41 | def get_title(self): 42 | return 'Foreach' 43 | 44 | def get_icon(self): 45 | return 'iob:arrow_return_right_32' 46 | 47 | def get_category(self): 48 | return 'Conditional' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | if not isinstance(input.value, list): 55 | print('List not provided to foreach') 56 | self.status = 'complete' 57 | return input 58 | 59 | -------------------------------------------------------------------------------- /elements/GenerateHashOfString.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | import hashlib 7 | 8 | class GenerateHashOfString(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = [] 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return False 18 | 19 | def setup_params(self): 20 | algs = [] 21 | for t in hashlib.algorithms_available: 22 | algs.append(t) 23 | self.params.append(ElementParameter(name='algorithms',displayName='Hash Algorithm',display=True, type='list',value='md5',allowedValues=algs, isVariableAllowed = False)) 24 | 25 | 26 | def get_status(self): 27 | return self.status 28 | 29 | def get_input_type(self): 30 | return 'string' 31 | 32 | def get_output(self): 33 | return self.output 34 | 35 | def get_output_type(self): 36 | return 'string' 37 | 38 | def get_params(self): 39 | return self.params 40 | 41 | def set_params(self, params = None): 42 | self.params = params or [] 43 | 44 | def get_description(self): 45 | return 'Generates a hash of the input value and returns it' 46 | 47 | def get_title(self): 48 | return 'Generate Hash of string' 49 | 50 | def get_icon(self): 51 | return 'iob:ios7_cog_outline_32' 52 | 53 | def get_category(self): 54 | return 'Utility' 55 | 56 | def get_type(self): 57 | return self.type 58 | 59 | def run(self, input=''): 60 | algo = self.get_param_by_name('algorithms') 61 | self.status = 'complete' 62 | return ElementValue(type=self.get_output_type(), value=hashlib.new(algo.value, input.value.encode('utf-8')).hexdigest()) 63 | -------------------------------------------------------------------------------- /elements/GetAddressfromLocation.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import location 6 | 7 | class GetAddressfromLocation(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return 'location' 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'address' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'Get address from location passed in.' 41 | 42 | def get_title(self): 43 | return 'Get Address from Location' 44 | 45 | def get_icon(self): 46 | return 'iob:location_32' 47 | 48 | def get_category(self): 49 | return 'Location' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input): 55 | self.status = 'complete' 56 | loc = location.reverse_geocode(input.value) 57 | return ElementValue(type = self.get_output_type(), value = loc) 58 | 59 | -------------------------------------------------------------------------------- /elements/GetBatteryDetails.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # The get battery code is highly based of the battery level example in pythonista 2.0 3 | 4 | from ElementBase import ElementBase 5 | from ElementParameter import ElementParameter 6 | from ElementValue import ElementValue 7 | from objc_util import * 8 | 9 | class GetBatteryDetails(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = None 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return False 19 | 20 | def setup_params(self): 21 | pass 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return None 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return 'battery' 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = None): 39 | self.params = params or [] 40 | 41 | def get_description(self): 42 | return 'Get details about the current state of the battery.' 43 | 44 | def get_title(self): 45 | return 'Get Battery Details' 46 | 47 | def get_icon(self): 48 | return 'iob:battery_half_32' 49 | 50 | def get_category(self): 51 | return 'Battery' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | def run(self, input=''): 57 | battery_states = {1: 'unplugged', 2: 'charging', 3: 'full'} 58 | device = ObjCClass('UIDevice').currentDevice() 59 | device.setBatteryMonitoringEnabled_(True) 60 | battery_percent = device.batteryLevel() * 100 61 | state = device.batteryState() 62 | device.setBatteryMonitoringEnabled_(False) 63 | batteryDetails = {'Level': battery_percent, 'State': battery_states.get(state, 'unknown')} 64 | self.status = 'complete' 65 | return ElementValue(type=self.get_output_type(), value=batteryDetails) 66 | 67 | -------------------------------------------------------------------------------- /elements/GetClipboardImage.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import clipboard 6 | 7 | class GetClipboardImage(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return None 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'image' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'This gets the an image from the system clipboard"' 41 | 42 | def get_title(self): 43 | return 'Get Clipboard Image' 44 | 45 | def get_icon(self): 46 | return 'iob:image_32' 47 | 48 | def get_category(self): 49 | return 'Image' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self): 55 | self.status = 'complete' 56 | img = clipboard.get_image() 57 | return ElementValue(type=self.get_output_type(), value=img) 58 | 59 | -------------------------------------------------------------------------------- /elements/GetClipboardText.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import clipboard 6 | 7 | class GetClipboardText(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return None 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'string' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return "This gets the text value of the system clipboard" 41 | 42 | def get_title(self): 43 | return 'Get Clipboard Text' 44 | 45 | def get_icon(self): 46 | return 'iob:ios7_copy_32' 47 | 48 | def get_category(self): 49 | return 'Text' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self): 55 | clip = clipboard.get() 56 | self.status = 'complete' 57 | return ElementValue(type = self.get_output_type(), value = clip) 58 | 59 | -------------------------------------------------------------------------------- /elements/GetCurrentLocation.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import location 6 | 7 | class GetCurrentLocation(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = [] 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | self.params.append(ElementParameter(name='title',displayName='Title',display=True,type='string',value='Current Location')) 20 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 21 | 22 | def get_status(self): 23 | return self.status 24 | 25 | def get_input_type(self): 26 | return None 27 | 28 | def get_output(self): 29 | return self.output 30 | 31 | def get_output_type(self): 32 | return 'location' 33 | 34 | def get_params(self): 35 | return self.params 36 | 37 | def set_params(self, params = None): 38 | self.params = params or [] 39 | 40 | def get_description(self): 41 | return 'Get current location of the device' 42 | 43 | def get_title(self): 44 | return 'Get Current Location' 45 | 46 | def get_icon(self): 47 | return 'iob:location_32' 48 | 49 | def get_category(self): 50 | return 'Location' 51 | 52 | def get_type(self): 53 | return self.type 54 | 55 | def run(self, input=''): 56 | location.start_updates() 57 | loc = location.get_location() 58 | location.stop_updates() 59 | titleParam = self.get_param_by_name('title').value 60 | loc['title'] = titleParam or 'Current Location' 61 | return ElementValue(type = self.get_output_type(), value = loc) 62 | 63 | -------------------------------------------------------------------------------- /elements/GetImagesfromAppextension.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import appex 6 | import console 7 | 8 | class GetImagesfromAppextension(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = [] 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return False 18 | 19 | def setup_params(self): 20 | self.params.append(ElementParameter(name='allowMultiple',displayName='Allow Multiple Images',display=True, type='bool',value=False)) 21 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return None 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return 'image' 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = None): 39 | self.params = params or [] 40 | 41 | def get_description(self): 42 | return 'Returns a list or single image from the app extension' 43 | 44 | def get_title(self): 45 | return 'Get Image(s) from App extension' 46 | 47 | def get_icon(self): 48 | return 'iob:archive_32' 49 | 50 | def get_category(self): 51 | return 'App Extension' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | def run(self, input=''): 57 | console.alert(title='Not complete', message='Does not work',button1='Ok',hide_cancel_button=True) 58 | if not appex.is_running_extension(): 59 | console.alert(title='Error', message='Not running from app extension',button1='Ok',hide_cancel_button=True) 60 | else: 61 | try: 62 | allowMultiple = self.get_param_by_name('allowMultiple').value 63 | if allowMultiple: 64 | images = appex.get_images() 65 | else: 66 | images = appex.get_image() 67 | ev = ElementValue(type='image',value=images) 68 | return ev 69 | except error: 70 | console.alert(title='Error', message='error: {}'.format(error),button1='Ok',hide_cancel_button=True) 71 | 72 | -------------------------------------------------------------------------------- /elements/GetLocationfromAddress.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import location 6 | 7 | class GetLocationfromAddress(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return 'address' 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'location' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'Get location from Address' 41 | 42 | def get_title(self): 43 | return 'Get Location from Address' 44 | 45 | def get_icon(self): 46 | return 'iob:location_32' 47 | 48 | def get_category(self): 49 | return 'Location' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input): 55 | self.status = 'complete' 56 | v = input.value[0] if isinstance(input.value, list) else input.value 57 | loc = location.geocode(v) 58 | if 'title' in v: 59 | loc[0]['title'] = v['title'] 60 | return ElementValue(type = self.get_output_type(), value = loc) 61 | 62 | -------------------------------------------------------------------------------- /elements/GetName.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class GetName(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return False 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return 'string' 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'Returns the name of the input ' 40 | 41 | def get_title(self): 42 | return 'Get Name' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_cog_32' 46 | 47 | def get_category(self): 48 | return 'Utility' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | self.status = 'complete' 55 | return ElementValue(type = self.get_output_type(), value = input.name) 56 | -------------------------------------------------------------------------------- /elements/GetScreenBrightness.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | from objc_util import * 7 | UIScreen = ObjCClass('UIScreen') 8 | 9 | class GetScreenBrightness(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = None 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return False 19 | 20 | def setup_params(self): 21 | pass 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return None 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return 'number' 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = None): 39 | self.params = params or [] 40 | 41 | def get_description(self): 42 | return 'Returns the screen brightness as a number between 0-100' 43 | 44 | def get_title(self): 45 | return 'Get Screen Brightness' 46 | 47 | def get_icon(self): 48 | return 'iob:iphone_32' 49 | 50 | def get_category(self): 51 | return 'Utility' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | def run(self, input=''): 57 | screen = UIScreen.mainScreen() 58 | val = screen.brightness() * 100 59 | return ElementValue(type = self.get_output_type(), value = val) 60 | -------------------------------------------------------------------------------- /elements/GetURLContents.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from ElementBase import ElementBase 4 | from ElementParameter import ElementParameter 5 | from ElementValue import ElementValue 6 | from PIL import Image 7 | try: 8 | import StringIO 9 | except: 10 | from io import StringIO 11 | 12 | import requests 13 | import console 14 | import time 15 | import copy 16 | 17 | class GetURLContents(ElementBase): 18 | def __init__(self): 19 | self.status = 'running' 20 | self.output = None 21 | self.params = [] 22 | self.type = 'Standard' 23 | self.setup_params() 24 | 25 | def can_handle_list(self): 26 | return False 27 | 28 | def setup_params(self): 29 | allowedValues = 'GET POST PUT DELETE'.split() 30 | self.params.append(ElementParameter(name='verb',displayName='Verb',display=True, type='list',value='GET',allowedValues=allowedValues, isVariableAllowed = False)) 31 | self.params.append(ElementParameter(name='params', displayName='Parameters', display=True, type='dictionary', value=None)) 32 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 33 | 34 | def get_status(self): 35 | return self.status 36 | 37 | def get_input_type(self): 38 | return 'url' 39 | 40 | def get_output(self): 41 | return self.output 42 | 43 | def get_output_type(self): 44 | return '*' 45 | 46 | def get_params(self): 47 | return self.params 48 | 49 | def set_params(self, params = None): 50 | self.params = params or [] 51 | 52 | def get_description(self): 53 | return 'Get the contents from a URL' 54 | 55 | def get_title(self): 56 | return 'Get URL Contents' 57 | 58 | def get_icon(self): 59 | return 'iob:ios7_download_32' 60 | 61 | def get_category(self): 62 | return 'Url' 63 | 64 | def get_type(self): 65 | return self.type 66 | 67 | def run(self, input=''): 68 | verbParam = self.get_param_by_name('verb') 69 | paramsParam = self.get_param_by_name('params') 70 | if verbParam.value == 'GET': 71 | if paramsParam.value == None: 72 | r = requests.get(input.value) 73 | else: 74 | r = requests.get(input.value, params=paramsParam.value) 75 | elif verbParam.value == 'POST': 76 | if paramsParam.value == None: 77 | r = requests.post(input.value) 78 | else: 79 | r = requests.get(input.value, data=paramsParam.value) 80 | 81 | elif verbParam.value == 'PUT': 82 | r = requests.put(input.value) 83 | elif verbParam.value == 'DELETE': 84 | r = requests.delete(input.value) 85 | self.status = 'complete' 86 | if r.status_code == 200: 87 | type = r.headers['content-type'].split('/')[0] 88 | value = Image.open(StringIO(r.content)) if type == 'image' else r.text 89 | return ElementValue(type=type, value=value) 90 | else: 91 | console.alert(title='Error',message=r.status_code,button1='Ok',hide_cancel_button=True) 92 | return ElementValue(type=None, value=None) 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /elements/GetVariable.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import console 6 | import copy 7 | try: 8 | import dialogs 9 | except ImportError: 10 | pass 11 | import ui 12 | 13 | class GetVariable(ElementBase): 14 | def __init__(self): 15 | self.status = 'running' 16 | self.output = None 17 | self.params = [] 18 | self.name = None 19 | self.type = 'Standard' 20 | self.setup_params() 21 | 22 | def can_handle_list(self): 23 | return False 24 | 25 | def setup_params(self): 26 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 27 | self.params.append(ElementParameter(name='VariableName',displayName='Variable Name',display=True,type='string')) 28 | 29 | def get_status(self): 30 | return self.status 31 | 32 | def get_input_type(self): 33 | return None 34 | 35 | def get_output(self): 36 | return self.output 37 | 38 | def get_output_type(self): 39 | return '*' 40 | 41 | def get_params(self): 42 | return self.params 43 | 44 | def set_params(self, params = None): 45 | self.params = params or [] 46 | 47 | def get_description(self): 48 | return 'Get a variable to be used within the flow.' 49 | 50 | def get_title(self): 51 | return 'Get Variable' 52 | 53 | def get_icon(self): 54 | return 'iob:ios7_gear_32' 55 | 56 | def get_category(self): 57 | return 'Utility' 58 | 59 | def selected_callback(self, item): 60 | self.name = item.name 61 | self.status = 'complete' 62 | self.get_param_by_name('fm:nav_view').value.pop_view() 63 | 64 | def get_type(self): 65 | return self.type 66 | 67 | def run(self): 68 | np = self.get_param_by_name('VariableName') 69 | rv = self.get_param_by_name('fm:runtime_variables') 70 | keysavailablestring = '' 71 | for k in rv.value: 72 | keysavailablestring += k + ' ' 73 | keysavailablemessage = 'Keys to choose from are: ' + keysavailablestring 74 | if (np.value or '').replace(' ', '') == '': 75 | try: 76 | key = dialogs.list_dialog('Vars',list(rv.value.keys())) 77 | self.name = key 78 | except : 79 | # if dialogs isnt available then fall back to console input 80 | self.name = console.input_alert(title='Please enter variable title', message=keysavailablemessage) 81 | 82 | else: 83 | self.name = np.value 84 | self.name = self.name or console.input_alert(title='Please enter variable title', message=keysavailablemessage) 85 | return rv.value[self.name].copyMe() 86 | 87 | -------------------------------------------------------------------------------- /elements/If.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class If(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = [] 11 | self.type = 'If' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return True 16 | 17 | def setup_params(self): 18 | self.params.append(ElementParameter(name='checkoption',displayName='Item to check',display=True,type='list',value='input value',allowedValues=['input value','input type'], isVariableAllowed=False)) 19 | self.params.append(ElementParameter(name='conditiontype',displayName='Condition Type',display=True,type='list',value='==',allowedValues=['==','<','>','>=','<=','not =='], isVariableAllowed = False)) 20 | self.params.append(ElementParameter(name='checkvalue',displayName='Check Value',display=True,type='string',value=None)) 21 | self.params.append(ElementParameter(name='ifresult',displayName='If Result',display=False,type='Boolean', value = None)) 22 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 23 | 24 | def get_status(self): 25 | return self.status 26 | 27 | def get_input_type(self): 28 | return '*' 29 | 30 | def get_output(self): 31 | return self.output 32 | 33 | def get_output_type(self): 34 | return '*' 35 | 36 | def get_params(self): 37 | return self.params 38 | 39 | def set_params(self, params = None): 40 | self.params = params or [] 41 | 42 | def get_description(self): 43 | return 'If conditional branching element' 44 | 45 | def get_title(self): 46 | return 'If' 47 | 48 | def get_icon(self): 49 | return 'iob:arrow_down_c_32' 50 | 51 | def get_category(self): 52 | return 'Conditional' 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self, input=''): 58 | ifresult = self.get_param_by_name('ifresult') 59 | ifcondition = self.get_param_by_name('conditiontype') 60 | checkoption = self.get_param_by_name('checkoption') 61 | checkvalue = self.get_param_by_name('checkvalue') 62 | if checkoption.value == 'input value': 63 | ifresult.value = self.checkvalue(input, ifcondition.value, checkvalue.value) 64 | elif checkoption.value == 'input type': 65 | ifresult.value = self.checktype(input, ifcondition.value, checkvalue.value) 66 | self.status = 'Complete' 67 | return input 68 | 69 | def checkvalue(self, value, condition, check_against): 70 | return self.ifcondition(value.value, check_against, condition) 71 | 72 | def checktype(self, value, condition, check_against): 73 | return self.ifcondition(value.type, check_against, condition) 74 | 75 | def ifcondition(self, value, check_against, condition): 76 | if condition == '==': 77 | return self.equals(value, check_against) 78 | elif condition == '<': 79 | return self.lessthan(value, check_against) 80 | elif condition == '>': 81 | return self.greaterthan(value, check_against) 82 | elif condition == '>=': 83 | return self.greaterthanorequal(value, check_against) 84 | elif condition == '<=': 85 | return self.lessthanorequals(value, check_against) 86 | elif condition == 'not ==': 87 | return self.notequal(value, check_against) 88 | return None 89 | 90 | def equals(self, value, checkvalue): 91 | return str(value) == str(checkvalue) 92 | 93 | def lessthan(self, value, checkvalue): 94 | return value < checkvalue 95 | 96 | def greaterthan(self, value, checkvalue): 97 | return value > checkvalue 98 | 99 | def lessthanorequals(self, value, checkvalue): 100 | return value <= checkvalue 101 | 102 | def greaterthanorequal(self, value, checkvalue): 103 | return value >= checkvalue 104 | 105 | def notequal(self, value, checkvalue): 106 | return not value == checkvalue 107 | -------------------------------------------------------------------------------- /elements/ListTest.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class ListTest(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | pass 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return None 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return 'string' 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return '' 40 | 41 | def get_title(self): 42 | return 'List Test' 43 | 44 | def get_icon(self): 45 | return 'iob:alert_32' 46 | 47 | def get_category(self): 48 | return 'Test' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | return ElementValue(type='string', value=['test','234','qwerty']) 55 | 56 | -------------------------------------------------------------------------------- /elements/Nothing.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class Nothing(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return True 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return None 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return 'Returns nothing, it makes sure nothing is passed to the next element' 40 | 41 | def get_title(self): 42 | return 'Nothing' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_cog_32' 46 | 47 | def get_category(self): 48 | return 'Utility' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | self.status = 'complete' 55 | return None 56 | -------------------------------------------------------------------------------- /elements/NumberInput.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | import console 7 | 8 | class NumberInput(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = None 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return False 18 | 19 | def setup_params(self): 20 | pass 21 | 22 | def get_status(self): 23 | return self.status 24 | 25 | def get_input_type(self): 26 | return None 27 | 28 | def get_output(self): 29 | return self.output 30 | 31 | def get_output_type(self): 32 | return 'number' 33 | 34 | def get_params(self): 35 | return self.params 36 | 37 | def set_params(self, params = None): 38 | self.params = params or [] 39 | 40 | def get_description(self): 41 | return 'Get a number from the user' 42 | 43 | def get_title(self): 44 | return 'Number Input' 45 | 46 | def get_icon(self): 47 | return 'iob:minus_round_32' 48 | 49 | def get_category(self): 50 | return 'Number' 51 | 52 | def get_type(self): 53 | return self.type 54 | 55 | def run(self, input=''): 56 | output = None 57 | while output == None or not output.isdigit(): 58 | output = console.input_alert(title='Input', message='Please enter a valid number') 59 | output = float(output) 60 | self.status = 'complete' 61 | return ElementValue(type = self.get_output_type(), value = output) 62 | -------------------------------------------------------------------------------- /elements/OpenLocationinAppleMaps.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | from objc_util import * 7 | 8 | class OpenLocationinAppleMaps(ElementBase): 9 | map_mode_dict = {'standard': 'm', 'satellite': 'k', 'hybrid': 'h', 'transit': 'r'} 10 | 11 | def __init__(self): 12 | self.status = 'running' 13 | self.output = None 14 | self.params = [] 15 | self.type = 'Standard' 16 | self.setup_params() 17 | 18 | def can_handle_list(self): 19 | return False 20 | 21 | def setup_params(self): 22 | self.params.append(ElementParameter(name='mapmode',displayName='Map Mode',display=True,type='list',value='standard',allowedValues=sorted(self.map_mode_dict.keys()),isVariableAllowed=False)) 23 | self.params.append(ElementParameter(name='zoom',displayName='Zoom',display=True,type='string',value='12',isVariableAllowed=False)) 24 | 25 | def get_status(self): 26 | return self.status 27 | 28 | def get_input_type(self): 29 | return 'location' 30 | 31 | def get_output(self): 32 | return self.output 33 | 34 | def get_output_type(self): 35 | return None 36 | 37 | def get_params(self): 38 | return self.params 39 | 40 | def set_params(self, params = None): 41 | self.params = params or [] 42 | 43 | def get_description(self): 44 | return 'Opens a location in the Apple Maps app' 45 | 46 | def get_title(self): 47 | return 'Open Location in Apple Maps' 48 | 49 | def get_icon(self): 50 | return 'iob:map_32' 51 | 52 | def get_category(self): 53 | return 'External App' 54 | 55 | def get_type(self): 56 | return self.type 57 | 58 | def run(self, input=''): 59 | mapmodeparam = self.get_param_by_name('mapmode') 60 | zoomparam = self.get_param_by_name('zoom') 61 | url = 'http://maps.apple.com/?ll={latitude},{longitude}'.format(**input.value) 62 | mm = self.map_mode_dict.get(mapmodeparam.value, '') 63 | if mm: 64 | url += '&t=' + mm 65 | if zoomparam.value: 66 | url += '&z=' + zoomparam.value 67 | uia = ObjCClass('UIApplication').sharedApplication() 68 | if not uia.openURL_(nsurl(url)): 69 | console.alert(title='Error oppening App',message='Something went wrong!',button1='Ok',hide_cancel_button=True) 70 | self.status = 'complete' 71 | 72 | -------------------------------------------------------------------------------- /elements/OpenLocationinGoogleMaps.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | from objc_util import * 6 | import console 7 | 8 | class OpenLocationinGoogleMaps(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = [] 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return False 18 | 19 | def setup_params(self): 20 | self.params.append(ElementParameter(name='mapmode',displayName='Map Mode',display=True,type='list',value='standard',allowedValues=['standard','streetview'],isVariableAllowed=False)) 21 | self.params.append(ElementParameter(name='viewmode',displayName='View Mode',display=True,type='list',value=None,allowedValues=['satellite', 'traffic', 'transit'],multipleAllowed=True,isVariableAllowed=False)) 22 | 23 | self.params.append(ElementParameter(name='zoom',displayName='Zoom',display=True,type='string',value='12',isVariableAllowed=False)) 24 | 25 | self.params.append(ElementParameter(name='query',displayName='Query in area',display=True,type='string')) 26 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 27 | 28 | def get_status(self): 29 | return self.status 30 | 31 | def get_input_type(self): 32 | return 'location' 33 | 34 | def get_output(self): 35 | return self.output 36 | 37 | def get_output_type(self): 38 | return None 39 | 40 | def get_params(self): 41 | return self.params 42 | 43 | def set_params(self, params = None): 44 | self.params = params or [] 45 | 46 | def get_description(self): 47 | return 'Opens a location in the Google Maps app' 48 | 49 | def get_title(self): 50 | return 'Open Location in Google Maps' 51 | 52 | def get_icon(self): 53 | return 'iob:map_32' 54 | 55 | def get_category(self): 56 | return 'External App' 57 | 58 | def get_type(self): 59 | return self.type 60 | 61 | def run(self, input=''): 62 | mapmodeparam = self.get_param_by_name('mapmode') 63 | viewsparam = self.get_param_by_name('viewmode') 64 | zoomparam = self.get_param_by_name('zoom') 65 | queryparam = self.get_param_by_name('query') 66 | url = 'comgooglemaps://?center={latitude},{longitude}'.format(**input.value) 67 | if mapmodeparam.value: 68 | url += '&mapmode='+ mapmodeparam.value 69 | if viewsparam.value: 70 | url += '&views=' + viewsparam.value 71 | if zoomparam.value: 72 | url += '&zoom=' + zoomparam.value 73 | if queryparam.value: 74 | url += '&q=' + queryparam.value 75 | uia = ObjCClass('UIApplication').sharedApplication() 76 | if not uia.openURL_(nsurl(url)): 77 | console.alert(title='Error oppening App',message='Is Google Maps app installed?',button1='Ok',hide_cancel_button=True) 78 | self.status = 'complete' 79 | 80 | -------------------------------------------------------------------------------- /elements/OpenURLin.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | from objc_util import * 7 | import console 8 | 9 | class OpenURLin(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = [] 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return False 19 | 20 | def setup_params(self): 21 | self.params.append(ElementParameter(name='app',displayName='App to Open in',display=True,type='list',value='safari',allowedValues=['safari','chrome'])) 22 | 23 | 24 | def get_status(self): 25 | return self.status 26 | 27 | def get_input_type(self): 28 | return 'url' 29 | 30 | def get_output(self): 31 | return self.output 32 | 33 | def get_output_type(self): 34 | return None 35 | 36 | def get_params(self): 37 | return self.params 38 | 39 | def set_params(self, params = None): 40 | self.params = params or [] 41 | 42 | def get_description(self): 43 | return 'Open Url in chosen application ' 44 | 45 | def get_title(self): 46 | return 'Open URL in' 47 | 48 | def get_icon(self): 49 | return 'iob:ios7_world_outline_32' 50 | 51 | def get_category(self): 52 | return 'Url' 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self, input=''): 58 | appparam = self.get_param_by_name('app') 59 | app = appparam.value 60 | uia = ObjCClass('UIApplication').sharedApplication() 61 | url = input.value 62 | if app == 'chrome': 63 | url = url.replace('https://','googlechromes://') 64 | url = url.replace('http://','googlechrome://') 65 | if not uia.openURL_(nsurl(url)): 66 | console.alert(title='Error oppening App',message='Something went wrong!',button1='Ok',hide_cancel_button=True) 67 | self.status = 'complete' 68 | 69 | 70 | -------------------------------------------------------------------------------- /elements/PickImagefromPhotos.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import photos 6 | 7 | class PickImagefromPhotos(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return None 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'image' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'Pick a image from photo library and returns it.' 41 | 42 | def get_title(self): 43 | return 'Pick Image from Photos' 44 | 45 | def get_icon(self): 46 | return 'iob:camera_32' 47 | 48 | def get_category(self): 49 | return 'Image' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self): 55 | img = photos.pick_asset().get_ui_image() 56 | return ElementValue(type = self.get_output_type(), value = img) 57 | 58 | -------------------------------------------------------------------------------- /elements/PlayAudio.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | from objc_util import * 6 | import threading 7 | import time 8 | 9 | class PlayAudio(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = [] 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return False 19 | 20 | def setup_params(self): 21 | self.params.append(ElementParameter(name='volume',displayName='Player Volume',display=True,type='slider',value=0.5)) 22 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 23 | 24 | def get_status(self): 25 | return self.status 26 | 27 | def get_input_type(self): 28 | return 'audio' 29 | 30 | def get_output(self): 31 | return self.output 32 | 33 | def get_output_type(self): 34 | return None 35 | 36 | def get_params(self): 37 | return self.params 38 | 39 | def set_params(self, params = None): 40 | self.params = params or [] 41 | 42 | def get_description(self): 43 | return 'Play audio that is input' 44 | 45 | def get_title(self): 46 | return 'Play Audio' 47 | 48 | def get_icon(self): 49 | return 'iob:volume_medium_32' 50 | 51 | def get_category(self): 52 | return 'Audio' 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self, input=''): 58 | volume = self.get_param_by_name('volume').value 59 | AVAudioPlayer = ObjCClass('AVAudioPlayer') 60 | player = AVAudioPlayer.alloc().initWithData_error_(input.value['audiodata'], None) 61 | player.volume = volume 62 | player.play() 63 | while player.playing(): 64 | time.sleep(0.1) 65 | player.release() 66 | self.status = 'complete' 67 | 68 | -------------------------------------------------------------------------------- /elements/Print.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class Print(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return True 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return '*' 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return None 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return "This prints the string that is in the input parameter" 40 | 41 | def get_title(self): 42 | return 'Print' 43 | 44 | def get_icon(self): 45 | return 'iob:ios7_printer_32' 46 | 47 | def get_category(self): 48 | return 'Utility' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input): 54 | print((input.value)) 55 | self.status = 'complete' 56 | 57 | -------------------------------------------------------------------------------- /elements/RecordAudio.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # Based on omz record audio example 3 | from ElementBase import ElementBase 4 | from ElementParameter import ElementParameter 5 | from ElementValue import ElementValue 6 | from objc_util import * 7 | import os 8 | import console 9 | 10 | AVAudioSession = ObjCClass('AVAudioSession') 11 | NSURL = ObjCClass('NSURL') 12 | AVAudioRecorder = ObjCClass('AVAudioRecorder') 13 | NSData = ObjCClass('NSData') 14 | 15 | class RecordAudio(ElementBase): 16 | def __init__(self): 17 | self.status = 'running' 18 | self.output = None 19 | self.params = [] 20 | self.type = 'Standard' 21 | self.setup_params() 22 | 23 | def can_handle_list(self): 24 | return False 25 | 26 | def setup_params(self): 27 | self.params.append(ElementParameter(name='tempfilename',displayName='Temporary File name',display=True,type='string',value='recording.m4a')) 28 | self.params.append(ElementParameter(name='removetempfile',displayName='Remove Temporary File',display=True,type='bool',value=True)) 29 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 30 | def get_status(self): 31 | return self.status 32 | 33 | def get_input_type(self): 34 | return None 35 | 36 | def get_output(self): 37 | return self.output 38 | 39 | def get_output_type(self): 40 | return 'audio' 41 | 42 | def get_params(self): 43 | return self.params 44 | 45 | def set_params(self, params = None): 46 | self.params = params or [] 47 | 48 | def get_description(self): 49 | return 'Record audio from Microphone input' 50 | 51 | def get_title(self): 52 | return 'Record Audio' 53 | 54 | def get_icon(self): 55 | return 'iob:ios7_mic_32' 56 | 57 | def get_category(self): 58 | return 'Audio' 59 | 60 | def get_type(self): 61 | return self.type 62 | 63 | def run(self, input=''): 64 | shared_session = AVAudioSession.sharedInstance() 65 | category_set = shared_session.setCategory_error_(ns('AVAudioSessionCategoryPlayAndRecord'), None) 66 | 67 | settings = {ns('AVFormatIDKey'): ns(1633772320), ns('AVSampleRateKey'):ns(44100.00), ns('AVNumberOfChannelsKey'):ns(2)} 68 | 69 | tempfilenameparam = self.get_param_by_name('tempfilename') 70 | removetempfileparam = self.get_param_by_name('removetempfile') 71 | output_path = os.path.abspath(tempfilenameparam.value) 72 | 73 | out_url = NSURL.fileURLWithPath_(ns(output_path)) 74 | recorder = AVAudioRecorder.alloc().initWithURL_settings_error_(out_url, settings, None) 75 | started_recording = recorder.record() 76 | try: 77 | if started_recording: 78 | while True: 79 | console.alert(title='Recording started', message='close this alert to end recording...') 80 | except KeyboardInterrupt: 81 | recorder.stop() 82 | recorder.release() 83 | data = NSData.dataWithContentsOfURL_(out_url) 84 | retfilepath = output_path 85 | if removetempfileparam.value: 86 | os.remove(output_path) 87 | retfilepath = None 88 | return ElementValue(type=self.get_output_type(), value={'type':'m4a','filename':tempfilenameparam.value, 'audiodata':data, 'filepath':retfilepath}, objcCopy = True) 89 | self.status = 'complete' 90 | -------------------------------------------------------------------------------- /elements/SaveImagetoCameraRoll.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import console 6 | import photos 7 | 8 | class SaveImagetoCameraRoll(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = None 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return False 18 | 19 | def setup_params(self): 20 | pass 21 | 22 | def get_status(self): 23 | return self.status 24 | 25 | def get_input_type(self): 26 | return 'image' 27 | 28 | def get_output(self): 29 | return self.output 30 | 31 | def get_output_type(self): 32 | return None 33 | 34 | def get_params(self): 35 | return self.params 36 | 37 | def set_params(self, params = None): 38 | self.params = params or [] 39 | 40 | def get_description(self): 41 | return 'Saves input image to Camera Roll' 42 | 43 | def get_title(self): 44 | return 'Save Image to Camera Roll' 45 | 46 | def get_icon(self): 47 | return 'iob:camera_32' 48 | 49 | def get_category(self): 50 | return 'Image' 51 | 52 | def get_type(self): 53 | return self.type 54 | 55 | def run(self, input): 56 | try: 57 | if not photos.save_image(input.value): 58 | console.alert("didn't work") 59 | except error: 60 | console.alert('error: {}'.format(error)) 61 | self.status = 'complete' 62 | 63 | -------------------------------------------------------------------------------- /elements/SetClipboardImage.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import clipboard 6 | 7 | class SetClipboardImage(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return 'image' 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return None 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = []): 37 | self.params = params 38 | 39 | def get_description(self): 40 | return "This sets the system clipboard with image input provided." 41 | 42 | def get_title(self): 43 | return 'Set Clipboard Image' 44 | 45 | def get_icon(self): 46 | return 'iob:image_32' 47 | 48 | def get_category(self): 49 | return 'Image' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input): 55 | clipboard.set_image(input.value) 56 | self.status = 'complete' 57 | -------------------------------------------------------------------------------- /elements/SetClipboardText.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import clipboard 6 | 7 | class SetClipboardText(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return 'string' 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return None 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params=[]): 37 | self.params=params 38 | 39 | def get_description(self): 40 | return "This sets the system clipboard with text input provided." 41 | 42 | def get_title(self): 43 | return 'Set Clipboard Text' 44 | 45 | def get_icon(self): 46 | return 'iob:ios7_copy_32' 47 | 48 | def get_category(self): 49 | return 'Text' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input): 55 | clipboard.set(input.value) 56 | self.status = 'complete' 57 | -------------------------------------------------------------------------------- /elements/SetName.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class SetName(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = [] 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return False 16 | 17 | def setup_params(self): 18 | self.params.append(ElementParameter(name='name',displayName='Name',display=True,type='string', value='')) 19 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return '*' 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return '*' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'Sets the name of the input value and returns it.' 41 | 42 | def get_title(self): 43 | return 'Set Name' 44 | 45 | def get_icon(self): 46 | return 'iob:ios7_cog_32' 47 | 48 | def get_category(self): 49 | return 'Utility' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input=''): 55 | name = self.get_param_by_name('name') 56 | input.name = name.value 57 | self.status = 'complete' 58 | return input 59 | -------------------------------------------------------------------------------- /elements/SetScreenBrightness.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | from objc_util import * 7 | UIScreen = ObjCClass('UIScreen') 8 | 9 | class SetScreenBrightness(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = None 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return False 19 | 20 | def setup_params(self): 21 | pass 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return 'number' 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return None 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = None): 39 | self.params = params or [] 40 | 41 | def get_description(self): 42 | return 'Set Screen Brightness based on input' 43 | 44 | def get_title(self): 45 | return 'Set Screen Brightness' 46 | 47 | def get_icon(self): 48 | return 'iob:iphone_32' 49 | 50 | def get_category(self): 51 | return 'Utility' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | def run(self, input=''): 57 | brightness = input.value 58 | if brightness > 100: 59 | brightness = 100 60 | elif brightness < 0: 61 | brightness = 0 62 | 63 | brightness = brightness/100 64 | screen = UIScreen.mainScreen() 65 | screen.setBrightness_(brightness) 66 | #time.sleep(0.3) 67 | self.status = 'complete' 68 | 69 | -------------------------------------------------------------------------------- /elements/SetVariable.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import console 6 | import copy 7 | 8 | class SetVariable(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = [] 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return True 18 | 19 | def setup_params(self): 20 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 21 | self.params.append(ElementParameter(name='VariableName',displayName='Variable Name',display=True,type='string')) 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return '*' 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return None 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = []): 39 | self.params = params 40 | 41 | def get_description(self): 42 | return 'Set a variable to be used within the flow.' 43 | 44 | def get_title(self): 45 | return 'Set Variable' 46 | 47 | def get_icon(self): 48 | return 'iob:ios7_gear_32' 49 | 50 | def get_category(self): 51 | return 'Utility' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | def run(self, input): 57 | np = self.get_param_by_name('VariableName') 58 | if np.value == None: 59 | name = console.input_alert('Please enter Variable name') 60 | else: 61 | name = np.value 62 | rv = self.get_param_by_name('fm:runtime_variables') 63 | rv.value[name] = copy.deepcopy(input) 64 | self.status = 'complete' 65 | -------------------------------------------------------------------------------- /elements/SetVolume.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | from objc_util import NSBundle, ObjCClass, on_main_thread 7 | NSBundle.bundleWithPath_('/System/Library/Frameworks/MediaPlayer.framework').load() 8 | MPVolumeView = ObjCClass('MPVolumeView') 9 | 10 | class SetVolume(ElementBase): 11 | def __init__(self): 12 | self.status = 'running' 13 | self.output = None 14 | self.params = None 15 | self.type = 'Standard' 16 | self.setup_params() 17 | 18 | def can_handle_list(self): 19 | return False 20 | 21 | def setup_params(self): 22 | pass 23 | 24 | def get_status(self): 25 | return self.status 26 | 27 | def get_input_type(self): 28 | return 'number' 29 | 30 | def get_output(self): 31 | return self.output 32 | 33 | def get_output_type(self): 34 | return None 35 | 36 | def get_params(self): 37 | return self.params 38 | 39 | def set_params(self, params = None): 40 | self.params = params or [] 41 | 42 | def get_description(self): 43 | return 'Changes System volume to input value between 0 - 100' 44 | 45 | def get_title(self): 46 | return 'Set Volume' 47 | 48 | def get_icon(self): 49 | return 'iob:ios7_volume_high_32' 50 | 51 | def get_category(self): 52 | return 'Utility' 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self, input=''): 58 | val = input.value 59 | if val > 100: 60 | val = 100 61 | elif val < 0: 62 | val = 0 63 | 64 | val = val/100 65 | set_system_volume(val) 66 | 67 | @on_main_thread 68 | def set_system_volume(value): 69 | volume_view = MPVolumeView.new().autorelease() 70 | for subview in volume_view.subviews(): 71 | if subview.isKindOfClass_(ObjCClass('UISlider')): 72 | subview.value = value 73 | break 74 | 75 | -------------------------------------------------------------------------------- /elements/ShowAlert.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import console 6 | 7 | class ShowAlert(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return True 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return '*' 26 | 27 | def get_output(self): 28 | self.output 29 | 30 | def get_output_type(self): 31 | return None 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params=[]): 37 | self.params = params 38 | 39 | def get_description(self): 40 | return "This show an alert from the string that is in the input parameter" 41 | 42 | def get_title(self): 43 | return 'Show Alert' 44 | 45 | def get_icon(self): 46 | return 'iob:alert_circled_32' 47 | 48 | def get_category(self): 49 | return 'Utility' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input): 55 | self.status = 'complete' 56 | input = str(input.value) 57 | title = __file__.rpartition('/')[2].partition('.')[0] or 'Message' 58 | console.alert(title=title, message=input, button1='Ok', hide_cancel_button=True) 59 | 60 | -------------------------------------------------------------------------------- /elements/ShowlocationonMap.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys 3 | if not '..' in sys.path: 4 | sys.path.append('..') 5 | import time 6 | 7 | from ElementBase import ElementBase 8 | from ElementParameter import ElementParameter 9 | from ElementValue import ElementValue 10 | from views.MapView import MapView 11 | 12 | sys.path.remove('..') 13 | class ShowlocationonMap(ElementBase): 14 | def __init__(self): 15 | self.status = 'running' 16 | self.output = None 17 | self.params = None 18 | self.type = 'Standard' 19 | self.setup_params() 20 | 21 | def can_handle_list(self): 22 | return True 23 | 24 | def setup_params(self): 25 | pass 26 | 27 | def get_status(self): 28 | return self.status 29 | 30 | def get_input_type(self): 31 | return 'location' 32 | 33 | def get_output(self): 34 | return self.output 35 | 36 | def get_output_type(self): 37 | return None 38 | 39 | def get_params(self): 40 | return self.params 41 | 42 | def set_params(self, params = None): 43 | self.params = params or [] 44 | 45 | def get_description(self): 46 | return 'Shows a location or list of on a map' 47 | 48 | def get_title(self): 49 | return 'Show location on Map' 50 | 51 | def get_icon(self): 52 | return 'iob:map_32' 53 | 54 | def get_category(self): 55 | return 'Location' 56 | 57 | def get_type(self): 58 | return self.type 59 | 60 | def run(self, input=''): 61 | m = MapView() 62 | 63 | if input.isList: 64 | for loc in input.value: 65 | title = str(loc['latitude']) + ', ' + str(loc['longitude']) 66 | if 'title' in list(loc.keys()): 67 | title = loc['title'] 68 | m.add_pin(lat = loc['latitude'], lon = loc['longitude'],title=title) 69 | else: 70 | title = str(input.value['latitude']) + ', ' + str(input.value['longitude']) 71 | if 'title' in list(input.value.keys()): 72 | title = input.value['title'] 73 | m.add_pin(lat = input.value['latitude'], lon = input.value['longitude'],title=title) 74 | m.present() 75 | while m.on_screen: 76 | time.sleep(0.1) 77 | self.status = 'complete' 78 | 79 | -------------------------------------------------------------------------------- /elements/Sleep.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | import time 7 | 8 | class Sleep(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = [] 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | return True 18 | 19 | def setup_params(self): 20 | self.params.append(ElementParameter(name='secondstosleep',displayName='Seconds to sleep',display=True,type='int',value=1)) 21 | 22 | self.params.append(ElementParameter(name='fm:runtime_variables',type='*')) 23 | 24 | def get_status(self): 25 | return self.status 26 | 27 | def get_input_type(self): 28 | return '*' 29 | 30 | def get_output(self): 31 | return self.output 32 | 33 | def get_output_type(self): 34 | return None 35 | 36 | def get_params(self): 37 | return self.params 38 | 39 | def set_params(self, params = None): 40 | self.params = params or [] 41 | 42 | def get_description(self): 43 | return 'Sleep for the number of seconds set' 44 | 45 | def get_title(self): 46 | return 'Sleep' 47 | 48 | def get_icon(self): 49 | return 'iob:ios7_time_32' 50 | 51 | def get_category(self): 52 | return 'Utility' 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self, input=''): 58 | t = self.get_param_by_name('secondstosleep') 59 | ttu = t.value 60 | if ttu < 0: 61 | ttu = 0 62 | time.sleep(ttu) 63 | -------------------------------------------------------------------------------- /elements/SpeakText.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import speech 6 | 7 | class SpeakText(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = [] 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | self.params.append(ElementParameter(name='speechlanguage',displayName='Speech Language',display=True,type='list',value='en_US',allowedValues=speech.get_languages(), isVariableAllowed=False)) 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return 'string' 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return None 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return 'Speak the text that is input to it' 41 | 42 | def get_title(self): 43 | return 'Speak Text' 44 | 45 | def get_icon(self): 46 | return 'iob:volume_medium_32' 47 | 48 | def get_category(self): 49 | return 'Text' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input): 55 | lang = self.get_param_by_name('speechlanguage') 56 | speech.say(input.value, lang.value) 57 | self.status = 'complete' 58 | -------------------------------------------------------------------------------- /elements/TakePhoto.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import photos 6 | import console 7 | import time 8 | 9 | class TakePhoto(ElementBase): 10 | def __init__(self): 11 | self.status = 'running' 12 | self.output = None 13 | self.params = None 14 | self.type = 'Standard' 15 | self.setup_params() 16 | 17 | def can_handle_list(self): 18 | return False 19 | 20 | def setup_params(self): 21 | pass 22 | 23 | def get_status(self): 24 | return self.status 25 | 26 | def get_input_type(self): 27 | return None 28 | 29 | def get_output(self): 30 | return self.output 31 | 32 | def get_output_type(self): 33 | return 'image' 34 | 35 | def get_params(self): 36 | return self.params 37 | 38 | def set_params(self, params = None): 39 | self.params = params or [] 40 | 41 | def get_description(self): 42 | return 'Take a photo using the devices camera and returns it.' 43 | 44 | def get_title(self): 45 | return 'Take Photo' 46 | 47 | def get_icon(self): 48 | return 'iob:ios7_camera_32' 49 | 50 | def get_category(self): 51 | return 'Image' 52 | 53 | def get_type(self): 54 | return self.type 55 | 56 | def run(self): 57 | self.status = 'complete' 58 | #console.alert(title='Known Issue',message='Take Photo sometimes freezes the ui and pythonista needs to be killed.',button1='Ok',hide_cancel_button=True) 59 | time.sleep(.5) 60 | return ElementValue(type = self.get_output_type(), value = photos.capture_image()) 61 | 62 | -------------------------------------------------------------------------------- /elements/Template.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | 6 | class {title}(ElementBase): 7 | def __init__(self): 8 | self.status = 'running' 9 | self.output = None 10 | self.params = None 11 | self.type = 'Standard' 12 | self.setup_params() 13 | 14 | def can_handle_list(self): 15 | return {canHandleList} 16 | 17 | def setup_params(self): 18 | pass 19 | 20 | def get_status(self): 21 | return self.status 22 | 23 | def get_input_type(self): 24 | return {input_type} 25 | 26 | def get_output(self): 27 | return self.output 28 | 29 | def get_output_type(self): 30 | return {output_type} 31 | 32 | def get_params(self): 33 | return self.params 34 | 35 | def set_params(self, params = None): 36 | self.params = params or [] 37 | 38 | def get_description(self): 39 | return '{description}' 40 | 41 | def get_title(self): 42 | return '{title_space}' 43 | 44 | def get_icon(self): 45 | return '{icon}' 46 | 47 | def get_category(self): 48 | return '{category}' 49 | 50 | def get_type(self): 51 | return self.type 52 | 53 | def run(self, input=''): 54 | #where the magic happens, put element logic here input is only used if input type is not None, return something if output type is not None, NOTE: for future changes please set self.status to 'complete' if successful or 'error' if error required 55 | pass 56 | -------------------------------------------------------------------------------- /elements/TextInput.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import console 6 | 7 | class TextInput(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = None 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | return False 17 | 18 | def setup_params(self): 19 | pass 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return None 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'string' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = None): 37 | self.params = params or [] 38 | 39 | def get_description(self): 40 | return "This displays a text box for the user to enter text" 41 | 42 | def get_title(self): 43 | return 'Text Input' 44 | 45 | def get_icon(self): 46 | return 'iob:document_text_32' 47 | 48 | def get_category(self): 49 | return 'Text' 50 | 51 | def show_input(self): 52 | self.output = console.input_alert('Please enter text') 53 | 54 | def get_type(self): 55 | return self.type 56 | 57 | def run(self): 58 | self.status = 'complete' 59 | self.show_input() 60 | return ElementValue(type = self.get_output_type(), value = self.output) 61 | 62 | -------------------------------------------------------------------------------- /elements/TexttoURL.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | import console 6 | 7 | class TexttoURL(ElementBase): 8 | def __init__(self): 9 | self.status = 'running' 10 | self.output = None 11 | self.params = [] 12 | self.type = 'Standard' 13 | self.setup_params() 14 | 15 | def can_handle_list(self): 16 | pass 17 | 18 | def setup_params(self): 19 | self.params.append(ElementParameter(name='protocol',displayName='Protocol',display=True,type='list',value='http://',allowedValues=['http://','https://','ftp://'],isVariableAllowed=False)) 20 | 21 | def get_status(self): 22 | return self.status 23 | 24 | def get_input_type(self): 25 | return 'string' 26 | 27 | def get_output(self): 28 | return self.output 29 | 30 | def get_output_type(self): 31 | return 'url' 32 | 33 | def get_params(self): 34 | return self.params 35 | 36 | def set_params(self, params = []): 37 | self.params = params 38 | 39 | def get_description(self): 40 | return 'Takes a string input and converts to a URL' 41 | 42 | def get_title(self): 43 | return 'Text to URL' 44 | 45 | def get_icon(self): 46 | return 'iob:ios7_world_outline_32' 47 | 48 | def get_category(self): 49 | return 'Url' 50 | 51 | def get_type(self): 52 | return self.type 53 | 54 | def run(self, input=''): 55 | stringUrl = input.value 56 | protoParam = self.get_param_by_name('protocol').value 57 | if not stringUrl: 58 | console.alert(title='Error',message='No url was given',button1='Ok',hide_cancel_button=True) 59 | return None 60 | if stringUrl[:len(protoParam)].find(protoParam) == -1: 61 | if not '//' in stringUrl: 62 | stringUrl = protoParam + stringUrl 63 | else: 64 | console.alert(title='Information',message='Url passed with incorrect protocol given',button1='Ok',hide_cancel_button=True) 65 | return ElementValue(type='url',value=stringUrl) 66 | 67 | -------------------------------------------------------------------------------- /elements/VibrateDevice.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from ElementBase import ElementBase 3 | from ElementParameter import ElementParameter 4 | from ElementValue import ElementValue 5 | from objc_util import * 6 | import ctypes 7 | 8 | class VibrateDevice(ElementBase): 9 | def __init__(self): 10 | self.status = 'running' 11 | self.output = None 12 | self.params = None 13 | self.type = 'Standard' 14 | self.setup_params() 15 | 16 | def can_handle_list(self): 17 | pass 18 | 19 | def setup_params(self): 20 | pass 21 | 22 | def get_status(self): 23 | return self.status 24 | 25 | def get_input_type(self): 26 | return '*' 27 | 28 | def get_output(self): 29 | return self.output 30 | 31 | def get_output_type(self): 32 | return None 33 | 34 | def get_params(self): 35 | return self.params 36 | 37 | def set_params(self, params = None): 38 | self.params = params or [] 39 | 40 | def get_description(self): 41 | return 'Vibrates the device' 42 | 43 | def get_title(self): 44 | return 'Vibrate Device' 45 | 46 | def get_icon(self): 47 | return 'iob:load_b_32' 48 | 49 | def get_category(self): 50 | return 'Utility' 51 | 52 | def get_type(self): 53 | return self.type 54 | 55 | def run(self, input=''): 56 | p = ctypes.CDLL(None).AudioServicesPlaySystemSound 57 | p.restype, p.argtypes = None, [ctypes.c_int32] 58 | vibrate_id = 0x00000fff 59 | p(vibrate_id) 60 | self.status = 'complete' 61 | 62 | -------------------------------------------------------------------------------- /elements/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | -------------------------------------------------------------------------------- /istaflow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | 4 | from __future__ import absolute_import 5 | from views import ElementListView, FlowCreationView, FlowsView, ElementManagementView, ElementCreationView, ElementRuntimeView, ToastView 6 | from managers import ElementManager, FlowManager, ThemeManager, HomeScreenManager, SettingsManager 7 | import ui 8 | import collections 9 | import console 10 | import os 11 | import dialogs 12 | import appex 13 | import sys 14 | import clipboard 15 | 16 | class ista(object): 17 | def __init__(self): 18 | self.hide_title_bar=True 19 | self.elements_view = None 20 | self.element_management_view = None 21 | self.element_creation_view = None 22 | self.flow_creation_view = None 23 | self.navigation_view = None 24 | self.flow_view = None 25 | self.element_runtime_view = None 26 | self.element_manager = None 27 | self.flow_manager = None 28 | self.theme_manager = None 29 | self.home_screen_manager = None 30 | self.elements = None 31 | self.selectedElements = [] 32 | self.selectedFlowType = '' 33 | self.flows = [] 34 | self.selectedFlow = None 35 | self.flow_passed_in = None 36 | self.settings_manager = None 37 | self.setup_settingsmanager() 38 | self.setup_thememanager() 39 | self.setup_homescreenmanager() 40 | self.setup_elementsmanager() 41 | self.setup_flowsmanager() 42 | self.get_valid_elements() 43 | self.get_flows(appex.is_running_extension()) 44 | self.setup_elementsview() 45 | self.setup_elementmanagementview() 46 | self.setup_elementcreationview() 47 | self.setup_flowsview() 48 | self.setup_flowcreationview() 49 | self.setup_elementruntimeview() 50 | self.setup_navigationview(self.flow_view) 51 | self.check_params() 52 | 53 | def check_params(self): 54 | if len(sys.argv) > 1: 55 | self.flow_passed_in = sys.argv[1] 56 | if self.flow_passed_in in self.flows: 57 | self.flowselectedcb(self.flow_passed_in, True) 58 | self.flow_passed_in = None 59 | else: 60 | console.alert('Error', self.flow_passed_in + ' does not exist!', button1='Ok',hide_cancel_button=True) 61 | self.flow_passed_in = None 62 | 63 | def setup_homescreenmanager(self): 64 | self.home_screen_manager = HomeScreenManager.HomeScreenManager() 65 | 66 | def setup_elementruntimeview(self): 67 | self.element_runtime_view = ElementRuntimeView.get_view(self.theme_manager) 68 | 69 | def setup_settingsmanager(self): 70 | self.settings_manager = SettingsManager.SettingsManager() 71 | 72 | def show_settingmanager(self, sender): 73 | self.settings_manager.show_form() 74 | 75 | def get_valid_elements(self): 76 | if self.element_manager == None: 77 | raise ValueError("element_manager hasnt been initialised") 78 | else: 79 | self.elements = {} 80 | elements_to_sort = self.element_manager.get_all_elements('valid') 81 | for element in elements_to_sort: 82 | if self.elements == None: 83 | self.elements = {} 84 | try: 85 | ele_value = self.elements[element.get_category()] 86 | ele_value.append(element) 87 | ele_value.sort(key=lambda x:x.get_title()) 88 | self.elements[element.get_category()] = ele_value 89 | except KeyError: 90 | self.elements[element.get_category()]=[element] 91 | self.elements = collections.OrderedDict(sorted(list(self.elements.items()), key=lambda t:t[0] )) 92 | 93 | def get_flows(self, appexonly): 94 | self.flows = self.flow_manager.get_flows(appexonly=appexonly) 95 | 96 | def show_elementruntimeview(self, element): 97 | self.element_runtime_view.data_source.load_element(element) 98 | self.element_runtime_view.reload() 99 | self.navigation_view.push_view(self.element_runtime_view) 100 | 101 | def show_flowcreationview(self, sender, autorun=False): 102 | self.validate_navigationview() 103 | self.selectedElements = [] 104 | if not self.selectedFlow == None: 105 | elements = self.flow_manager.get_element_details_for_flow(self.selectedFlow) 106 | for element in elements: 107 | e = self.element_manager.get_element_with_title(element['title']) 108 | if e == None: 109 | raise ValueError('Flow has an element that isn\'t available. Title: ' + element['title']) 110 | if not e.get_params() == None: 111 | for p in e.get_params(): 112 | if p.name in list(element['params'].keys()): 113 | temp = element['params'][p.name] 114 | if(isinstance(temp, dict)): 115 | p.value = temp['value'] 116 | p.useVariable = temp['useVariable'] 117 | p.variableName = temp['variableName'] 118 | p.askAtRuntime = temp['askAtRuntime'] 119 | else: 120 | p.value = temp 121 | self.selectedElements.append(e) 122 | type = self.flow_manager.get_type_for_flow(self.selectedFlow) 123 | title = os.path.splitext(self.selectedFlow)[0] 124 | self.flow_creation_view.name = title 125 | self.flow_creation_view.data_source.title = title 126 | self.flow_creation_view.data_source.flowType = type 127 | self.selectedFlow = None 128 | if autorun: 129 | self.runflow(None) 130 | else: 131 | self.flow_creation_view.data_source.title = '' 132 | self.flow_creation_view.name = 'New Flow' 133 | self.flow_creation_view.data_source.flowType = 'Normal' 134 | self.flow_creation_view.data_source.elements = self.selectedElements 135 | self.flow_creation_view.data_source.update_buttons() 136 | self.flow_creation_view.reload_data() 137 | 138 | if self.flow_creation_view == None: 139 | raise ValueError("flow_creation_view hasnt been initialised") 140 | else: 141 | self.flow_creation_view.editing = False 142 | self.navigation_view.push_view(self.flow_creation_view) 143 | 144 | def show_assetpicker(self, view): 145 | self.navigation_view.push_view(view) 146 | 147 | def close_assetpicker(self, view): 148 | self.navigation_view.pop_view(view) 149 | 150 | def setup_navigationview(self, initview): 151 | initview.right_button_items = [ui.ButtonItem(title='Add Flow', action=self.show_flow_choice_menu)] 152 | initview.left_button_items = [ui.ButtonItem(title='Elements', action=self.show_elementmanagementview),ui.ButtonItem(title='Settings',action=self.show_settingmanager)] 153 | self.navigation_view = ui.NavigationView(initview) 154 | self.navigation_view.bar_tint_color=self.theme_manager.main_bar_colour 155 | self.navigation_view.tint_color = self.theme_manager.main_tint_colour 156 | self.navigation_view.background_color = self.theme_manager.main_background_colour 157 | self.navigation_view.title_color = self.theme_manager.main_title_text_colour 158 | 159 | @ui.in_background 160 | def show_flow_choice_menu(self,sender): 161 | option = console.alert(title='Create Flow', message='Would you like to import or create?', hide_cancel_button=True, button1='Import from Clipboard', button2='Create') 162 | if option == 1: 163 | title = '' 164 | while title == '': 165 | title = console.input_alert(title='Please enter title for flow', message='If flow exists it will be copied over') 166 | 167 | self.flow_manager.create_from_export(title, clipboard.get()) 168 | self.get_flows(appex.is_running_extension()) 169 | self.flow_view.data_source.flows = self.flows 170 | self.flow_view.reload_data() 171 | elif option == 2: 172 | self.show_flowcreationview(sender) 173 | def setup_flowsmanager(self): 174 | self.flow_manager = FlowManager.FlowManager(self.elementchange) 175 | 176 | def setup_elementsmanager(self): 177 | self.element_manager = ElementManager.ElementManager() 178 | 179 | def setup_thememanager(self): 180 | self.theme_manager = ThemeManager.ThemeManager() 181 | 182 | def setup_elementsview(self): 183 | self.elements_view = ElementListView.get_view(self.elements, self.elementselectedcb, self.theme_manager) 184 | 185 | def setup_elementmanagementview(self): 186 | self.element_management_view = ElementManagementView.get_view(self.elements, self.theme_manager) 187 | 188 | def setup_elementcreationview(self): 189 | self.element_creation_view = ElementCreationView.get_view(savecb=self.create_element, apcb=self.show_assetpicker, capcb = self.close_assetpicker, thememanager = self.theme_manager) 190 | 191 | def setup_flowsview(self): 192 | self.flow_view = FlowsView.get_view(self.flows, self.flowselectedcb,self.deleteflow, self.theme_manager) 193 | 194 | def setup_flowcreationview(self): 195 | self.flow_creation_view = FlowCreationView.get_view(elements = self.selectedElements, saveCallBack = self.savecb, addElementAction = self.show_elementsview, saveFlowAction = self.saveflow, runFlowAction = self.runflow, showElementRuntimeView = self.show_elementruntimeview, thememanager=self.theme_manager, flowType = self.selectedFlowType, flowTypeSelection = self.show_flowtypeselection, saveToHomeScreenAction = self.addFlowToHomeScreen, copyFlowToClipboardCallBack=self.copyFlowToClipboard) 196 | 197 | @ui.in_background 198 | def show_flowtypeselection(self): 199 | self.selectedFlowType = self.flow_creation_view.data_source.flowType 200 | type = dialogs.list_dialog(title='Flow Type', items=['Normal','Action Extension']) 201 | if not type == None: 202 | self.selectedFlowType = type 203 | self.flow_creation_view.data_source.flowType = self.selectedFlowType 204 | self.flow_creation_view.reload_data() 205 | 206 | def deleteflow(self, flowtitle): 207 | self.flow_manager.delete_flow(flowtitle) 208 | 209 | def copyFlowToClipboard(self): 210 | if self.flow_creation_view.data_source.title == '': 211 | console.alert(title='Error',message='Please enter a title',button1='Ok',hide_cancel_button=True) 212 | else: 213 | try: 214 | self.flow_manager.copy_Flow_To_Clipboard(self.flow_creation_view.data_source.title+'.flow') 215 | console.alert(title='Success', message='Flow copied to clipboard', hide_cancel_button=True, button1='Ok') 216 | except FileNotFoundError: 217 | console.alert(title='Error Sharing', message='Flow not found, have you saved your flow?') 218 | 219 | #@ui.in_background 220 | def saveflow(self,sender): 221 | if self.flow_creation_view.data_source.title == '': 222 | self.show_alert(title='Error', message='Please enter a title') 223 | #console.alert(title='Error',message='Please enter a title',button1='Ok',hide_cancel_button=True) 224 | else: 225 | if not self.flow_creation_view.data_source.oldtitle == '': 226 | self.deleteflow(self.flow_creation_view.data_source.oldtitle+'.flow') 227 | self.selectedFlowType = self.flow_creation_view.data_source.flowType 228 | self.flow_manager.save_flow(self.flow_creation_view.data_source.title, self.selectedElements, self.selectedFlowType) 229 | self.show_alert(title='Success', message='Flow has been saved') 230 | #console.alert(title='Success',message='Flow has been saved',button1='Ok',hide_cancel_button=True) 231 | self.get_flows(appex.is_running_extension()) 232 | self.flow_view.data_source.flows = self.flows 233 | self.flow_view.reload_data() 234 | 235 | #@ui.in_background 236 | def addFlowToHomeScreen(self): 237 | if self.flow_creation_view.data_source.title == '': 238 | self.show_alert(title='Error', message='Please enter a title') 239 | #console.alert(title='Error',message='Please enter a title',button1='Ok',hide_cancel_button=True) 240 | else: 241 | self.home_screen_manager.show_form(self.flow_creation_view.data_source.title+'.flow') 242 | 243 | def validate_navigationview(self): 244 | if self.navigation_view == None: 245 | raise ValueError("navigation_view hasn't been initialised") 246 | 247 | def show_elementsview(self, sender): 248 | self.validate_navigationview() 249 | if self.elements_view == None: 250 | raise ValueError("elements_view hasnt been initialised") 251 | else: 252 | self.navigation_view.push_view(self.elements_view) 253 | 254 | def show_elementmanagementview(self, sender): 255 | self.validate_navigationview() 256 | if self.element_management_view == None: 257 | raise ValueError("element_management_view hasnt been initialised") 258 | else: 259 | self.element_management_view.right_button_items = [ui.ButtonItem(title='Create Element', action=self.show_elementcreationview)] 260 | self.navigation_view.push_view(self.element_management_view) 261 | 262 | def show_elementcreationview(self, sender): 263 | self.validate_navigationview() 264 | if self.element_creation_view == None: 265 | raise ValueError("element_creation_view hasnt been initialised") 266 | else: 267 | self.navigation_view.push_view(self.element_creation_view) 268 | 269 | def close_elementsview(self): 270 | if self.elements_view == None: 271 | raise ValueError("elements_view hasnt been initialised") 272 | else: 273 | self.navigation_view.pop_view(self.elements_view) 274 | 275 | def close_flowcreationview(self): 276 | if self.flow_creation_view == None: 277 | raise ValueError("flow_creation_view hasnt been initialised") 278 | else: 279 | self.navigation_view.pop_view(self.flow_creation_view) 280 | 281 | def show_mainview(self): 282 | self.validate_navigationview() 283 | #ui seems to need to be portrait otherwise capture image view breaks 284 | self.navigation_view.present(orientations=['portrait'], title_bar_color=self.theme_manager.main_bar_colour, hide_title_bar=self.hide_title_bar) 285 | show_setting = self.settings_manager.get_setting_by_key('displayHowToClose') 286 | if show_setting == None: 287 | show_setting = True 288 | if self.hide_title_bar and show_setting: 289 | ToastView.display_toast(view=self.navigation_view, help_text='Close by swiping down with two fingers') 290 | 291 | def elementselectedcb(self, element): 292 | self.selectedElements.append(element) 293 | extraElements = self.element_manager.get_extra_elements_for_element(element) 294 | for ele in extraElements: 295 | self.selectedElements.append(ele) 296 | self.flow_creation_view.data_source.elements=self.selectedElements 297 | self.flow_creation_view.reload_data() 298 | self.close_elementsview() 299 | 300 | def savecb(self, saveElements): 301 | self.selectedElements = saveElements 302 | self.close_flowcreationview() 303 | 304 | def flowselectedcb(self, flow, autorun = False): 305 | self.selectedFlow = flow 306 | self.selectedFlowType = self.flow_manager.get_type_for_flow(flow) 307 | try: 308 | self.show_flowcreationview(None, autorun) 309 | except ValueError as e: 310 | self.show_alert(title='Error', message=str(e)) 311 | 312 | @ui.in_background 313 | def show_alert(self, title, message): 314 | console.alert(title=title, message=message, button1='Ok', hide_cancel_button=True) 315 | 316 | def create_element(self, title, inputType, outputType, description, icon, category, canHandleList): 317 | 318 | self.element_manager.create_element(title=title, inputType=inputType, outputType=outputType, description=description, icon=icon, category=category, canHandleList=canHandleList) 319 | console.hud_alert('Element created') 320 | self.get_valid_elements() 321 | self.element_management_view.data_source.elements = self.elements 322 | self.element_management_view.reload_data() 323 | self.elements_view.data_source.elements = self.elements 324 | self.elements_view.reload_data() 325 | self.element_creation_view.reload() 326 | 327 | #@ui.in_background 328 | def runflow(self,sender): 329 | try: 330 | self.flow_creation_view.reload() 331 | ret, message= self.flow_manager.run_flow(self.selectedElements,self.navigation_view, self.selectedFlowType) 332 | if ret: 333 | self.show_alert(title='Complete', message=message) 334 | #console.alert(title='Complete',message=message,button1='Ok',hide_cancel_button=True) 335 | else: 336 | self.show_alert(title='Error', message=message) 337 | #console.alert(title='Error',message=message,button1='Ok',hide_cancel_button=True) 338 | except ValueError as e: 339 | self.show_alert(title='Error', message=str(e)) 340 | #console.alert(str(e)) 341 | self.flow_creation_view.data_source.currentElementNumber = -1 342 | self.flow_creation_view.reload() 343 | 344 | def elementchange(self, currentelementnumber): 345 | self.flow_creation_view.data_source.currentElementNumber = currentelementnumber 346 | self.flow_creation_view.reload() 347 | 348 | def main(): 349 | m = ista() 350 | m.show_mainview() 351 | 352 | if __name__ == '__main__': 353 | main() 354 | 355 | -------------------------------------------------------------------------------- /managers/ElementManager.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | import os 7 | # from os import listdir # -> Is not an issue however it is neater to just import os 8 | # from os.path import isfile, join, splitext # --> join is a builtin method causing name space issues 9 | from importlib import import_module 10 | import sys 11 | import copy 12 | import imp 13 | sys.path.append('elements') 14 | 15 | 16 | class ElementManager (object): 17 | def __init__(self): 18 | self.elementsFolder = 'elements' 19 | self.elementExclusionList = ('ElementBase.py','__init__.py','Template.py','ElementParameter.py','ElementValue.py') 20 | 21 | self.requiredElementInstanceMethods = ('get_status', 'get_input', 'get_output','get_input_type', 'get_output_type', 'get_params','set_params', 'get_description', 'get_title','get_category', 'get_icon', 'run') 22 | self.extraElements = {'For':['End For'], 'Foreach':['End Foreach'],'If':['Else','End If']} 23 | sys.path.append('elements') 24 | 25 | def get_all_elements(self, element_type=None): 26 | elements = [ 27 | os.path.splitext(f) for f in os.listdir(self.elementsFolder) 28 | if os.path.isfile(os.path.join(self.elementsFolder, f)) and 29 | not f in self.elementExclusionList 30 | ] 31 | validElements = [] 32 | invalidElements = [] 33 | for i in elements: 34 | mod = import_module(i[0]) 35 | try: 36 | imp.reload(mod) 37 | except NameError: 38 | try: 39 | from importlib import reload 40 | imp.reload(mod) 41 | except ImportError: 42 | from imp import reload 43 | imp.reload(mod) 44 | klass = getattr(mod,i[0]) 45 | klassIsValid = True 46 | for method in self.requiredElementInstanceMethods: 47 | if not hasattr(klass, method): 48 | klassIsValid = False 49 | break 50 | if klassIsValid: 51 | validElements.append(klass()) 52 | else: 53 | invalidElements.append(klass()) 54 | 55 | if not element_type: 56 | return {'valid':validElements, 'invalid':invalidElements} 57 | elif element_type == 'valid': 58 | return validElements 59 | elif element_type == 'invalid': 60 | return inValidElements 61 | else: 62 | return [] 63 | 64 | def get_extra_elements_for_element(self, element): 65 | elementsToReturn = [] 66 | if element.get_title() in self.extraElements: 67 | for ele in self.extraElements[element.get_title()]: 68 | elementsToReturn.append(self.get_element_with_title(ele)) 69 | return elementsToReturn 70 | 71 | def get_element_class(self, element): 72 | # The element class is element.__class__ 73 | return element.__class__.__name__ 74 | 75 | def get_element_with_title(self, title): 76 | elements = self.get_all_elements('valid') 77 | for element in elements: 78 | if element.get_title() == title: 79 | return copy.deepcopy(element) 80 | return None 81 | 82 | def create_element(self, title, inputType, outputType, description, icon, category, canHandleList): 83 | if not inputType == None: 84 | inputType = "'"+inputType+"'" 85 | if not outputType == None: 86 | outputType = "'"+outputType+"'" 87 | titleValidated = title.replace(" ","") 88 | templatePath = os.path.join(self.elementsFolder, 'Template.py') 89 | elementPath = os.path.join(self.elementsFolder, "{fileName}.py".format(fileName=titleValidated)) 90 | if os.path.isfile(elementPath): 91 | print('Element Already Exists') 92 | return 93 | with open(templatePath, 'r') as f: 94 | # str.format thinks that on line 8 ```self.params = {}``` and 95 | # on line 27 ```def set_params(self, params = {})``` are fomatting values 96 | tem = f.read().format(**{'title':titleValidated, 'title_space':title, 'input_type':inputType, 'output_type':outputType,'description':description,'icon':icon,'category':category,'canHandleList':canHandleList}) 97 | with open(elementPath, 'w') as f: 98 | f.write(tem) 99 | 100 | 101 | if __name__ == '__main__': 102 | sys.path[-1] = '../elements' 103 | ElementManager.elementsFolder = '../elements' 104 | manager = ElementManager() 105 | print((manager.get_all_elements())) 106 | print((manager.get_element_with_title('newElement'))) 107 | manager.create_element('newElement1') 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /managers/FlowManager.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | import json 5 | import os 6 | import time 7 | import copy 8 | import appex 9 | import sys 10 | import clipboard 11 | import traceback 12 | 13 | class FlowManager (object): 14 | def __init__(self, elementchangecb): 15 | self.elementchangecb = elementchangecb 16 | self.runtime_variables = {} 17 | self.nav_view = None 18 | self.dir = 'flows/' 19 | if not os.path.exists(self.dir): 20 | os.mkdir(self.dir) 21 | 22 | def get_flows(self, appexonly): 23 | flows = os.listdir(self.dir) 24 | if appexonly: 25 | return [f for f in flows if self.get_type_for_flow(f) == 'Action Extension'] 26 | else: 27 | return flows 28 | 29 | def save_flow(self, title, elements, type): 30 | names = [] 31 | for ele in elements: 32 | params = {p.name: {'value':p.value if not p.askAtRuntime else None, 'useVariable':p.useVariable, 'variableName':p.variableName if not p.askAtRuntime else '', 'askAtRuntime':p.askAtRuntime} for p in (ele.get_params() or []) if p.display} 33 | ob = {'title':ele.get_title(),'params':params} 34 | names.append(ob) 35 | fl = {'type':type,'elements':names} 36 | f = open(self.dir+title+'.flow','w') 37 | f.write(json.JSONEncoder().encode(fl)) 38 | f.close() 39 | 40 | def delete_flow(self, title): 41 | if os.path.exists(self.dir+title): 42 | os.remove(self.dir+title) 43 | 44 | def get_element_details_for_flow(self, flow): 45 | with open(self.dir+flow,'r') as f: 46 | return json.JSONDecoder().decode(f.read())['elements'] 47 | 48 | def get_type_for_flow(self, flow): 49 | with open(self.dir+flow,'r') as f: 50 | return json.JSONDecoder().decode(f.read())['type'] 51 | 52 | def run_flow(self, elements, navview, type): 53 | output = None 54 | prevOutputType = None 55 | elementNumber = 1 56 | foreachstore = None 57 | forstore = None 58 | ifstore = None 59 | self.nav_view = navview 60 | self.runtime_variables = {} 61 | if type == 'Action Extension' and not appex.is_running_extension(): 62 | return False, 'Flow type: Action Extension flow not running in extension' 63 | try: 64 | while elementNumber<= len(elements): 65 | element = elements[elementNumber-1] 66 | self.elementchangecb(elementNumber) 67 | elementType = element.get_type() 68 | self.set_runtime_element_params(element) 69 | if element.get_input_type() == None: 70 | output = element.run() 71 | else: 72 | if prevOutputType == element.get_input_type() or element.get_input_type() == '*': 73 | if output == None or not isinstance(output.value,list) or element.can_handle_list(): 74 | output = element.run(output) 75 | else: 76 | raise ValueError('List provided to ' + element.get_title() + ' and cant handle list') 77 | else: 78 | raise ValueError('Invalid input type provided to ' + element.get_title()) 79 | self.get_runtime_element_params(element) 80 | prevOutputType = output.type if output else element.get_output_type() 81 | if elementType == 'Foreach': 82 | foreachstore = [output.copyMe(),elementNumber,len(output.value),0] 83 | output.value = foreachstore[0].value[foreachstore[3]] 84 | self.handle_foreach() 85 | elif elementType == 'EndForeach': 86 | foreachstore[3] += 1 87 | if foreachstore[3] < foreachstore[2]: 88 | elementNumber = foreachstore[1] 89 | output.type = foreachstore[0].type 90 | prevOutputType = output.type 91 | output.value = foreachstore[0].value[foreachstore[3]] 92 | else: 93 | foreachstore = None 94 | output = None 95 | elif elementType == 'For': 96 | forcount = element.get_param_by_name('forcount') 97 | if forcount == None: 98 | return False, 'For element count parameter not setup correctly' 99 | forstore = [elementNumber,forcount.value,0] 100 | elif elementType == 'EndFor': 101 | output = None 102 | forstore[2] += 1 103 | if forstore[2] < forstore[1]: 104 | elementNumber = forstore[0] 105 | else: 106 | forstore = None 107 | elif elementType == 'If': 108 | ifresult = element.get_param_by_name('ifresult') 109 | if ifresult == None or ifresult.value == None: 110 | return False, 'Result from if not found or is None, uisomething is wrong' 111 | if not ifresult.value: 112 | elsefound= False 113 | i = elementNumber 114 | skipnumber = 0 115 | while not elsefound: 116 | if i >= len(elements): 117 | return False, 'Else not found for if block' 118 | if elements[i].get_type() == 'If': 119 | skipnumber = skipnumber + 1 120 | if elements[i].get_type() == 'Else': 121 | if skipnumber > 0: 122 | skipnumber = skipnumber - 1 123 | i = i + 1 124 | else: 125 | elsefound = True 126 | elementNumber = i+1 127 | else: 128 | i = i+1 129 | elif elementType == 'Else': 130 | endiffound = False 131 | i = elementNumber 132 | skipnumber = 0 133 | while not endiffound: 134 | if i >= len(elements): 135 | return False, 'End If not found for if block' 136 | if elements[i].get_type() == 'If': 137 | skipnumber = skipnumber + 1 138 | if elements[i].get_type() == 'EndIf': 139 | if skipnumber > 0: 140 | skipnumber = skipnumber - 1 141 | i = i + 1 142 | else: 143 | endiffound = True 144 | elementNumber = i 145 | else: 146 | i = i+1 147 | elif elementType == 'EndIf': 148 | output = None 149 | ifstore = None 150 | 151 | elementNumber += 1 152 | elementNumber = 0 153 | self.elementchangecb(elementNumber) 154 | return True, 'Flow completed successfully' 155 | except KeyboardInterrupt: 156 | return False, 'Cancelled by user' 157 | except: 158 | return False, str(sys.exc_info()[1]) 159 | 160 | def set_runtime_element_params(self, element): 161 | params = element.get_params() 162 | if params: 163 | for param in params: 164 | if param.name =='fm:runtime_variables': 165 | param.value = self.runtime_variables 166 | if param.name == 'fm:nav_view': 167 | param.value = self.nav_view 168 | if param.useVariable: 169 | element.get_runtime_variable_for_parameter(param) 170 | element.set_params(params) 171 | 172 | def get_runtime_element_params(self, element): 173 | for param in element.get_params() or []: 174 | if param.name == 'fm:runtime_variables': 175 | self.runtime_variables = param.value 176 | 177 | def handle_foreach(self): 178 | pass 179 | 180 | def copy_Flow_To_Clipboard(self, title): 181 | with open(self.dir+title,'r') as f: 182 | clipboard.set(f.read()) 183 | 184 | def create_from_export(self, title, contents): 185 | f = open(self.dir+title+'.flow','w') 186 | f.write(contents) 187 | f.close() 188 | 189 | 190 | -------------------------------------------------------------------------------- /managers/HomeScreenManager.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # script modified from script in omz forum. 3 | import ui 4 | import dialogs 5 | from managers import WebClipper 6 | class HomeScreenManager (object): 7 | def __init__(self): 8 | self.fields = [{'type':'text','key':'Label','title':'Icon Label'}] 9 | 10 | @ui.in_background 11 | def show_form(self, flow_name): 12 | data = dialogs.form_dialog(title='Icon details', fields=self.fields ) 13 | WebClipper.save(data['Label'], flow_name) 14 | -------------------------------------------------------------------------------- /managers/SettingsManager.py: -------------------------------------------------------------------------------- 1 | import dialogs 2 | import json 3 | import os 4 | class SettingsManager (object): 5 | def __init__(self): 6 | self.fields = [{'type':'switch','key':'displayHowToClose','title':'Display how to close', 'value':True}] 7 | self.data = None 8 | self.filename = 'settings.json' 9 | self.load_file() 10 | self.update_fields() 11 | 12 | def show_form(self): 13 | self.data = dialogs.form_dialog(title='Settings', fields=self.fields ) 14 | if not self.data == None: 15 | self.save_file() 16 | self.update_fields() 17 | 18 | def save_file(self): 19 | f = open(self.filename,'w+') 20 | f.write(json.JSONEncoder().encode(self.data)) 21 | f.close() 22 | 23 | def load_file(self): 24 | if not os.path.isfile(self.filename): 25 | g = open(self.filename,'w+') 26 | g.write(json.JSONEncoder().encode({})) 27 | g.close() 28 | with open(self.filename,'r') as f: 29 | self.data = json.JSONDecoder().decode(f.read()) 30 | 31 | def update_fields(self): 32 | if not self.data == None: 33 | for f in self.fields: 34 | if f['key'] in self.data.keys(): 35 | f['value'] = self.data[f['key']] 36 | 37 | def get_setting_by_key(self, key): 38 | self.load_file() 39 | if not self.data == None: 40 | if key in self.data.keys(): 41 | return self.data[key] 42 | return self.get_field_value_by_key(key) 43 | 44 | def get_field_value_by_key(self,key): 45 | for f in self.fields: 46 | if f['key'] == key: 47 | return f['value'] 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /managers/ThemeManager.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class ThemeManager (object): 3 | def __init__(self): 4 | self.main_background_colour = .85, .85, .85 5 | self.main_text_colour = .31, .31, .31 6 | self.main_bar_colour = .85,.85,.85 7 | self.main_tint_colour = .31,.31,.31 8 | self.main_title_text_colour = .31,.31,.31 9 | self.running_cell_background_colour = .1, .18, 1.0 10 | self.running_cell_text_colour = 1.0, 1.0, 1.0 11 | -------------------------------------------------------------------------------- /managers/WebClipper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # modified scripts from 3 | # https://forum.omz-software.com/topic/2271/beta-suggestion-safariviewcontroller/2 4 | 5 | from __future__ import absolute_import 6 | from __future__ import print_function 7 | import uuid, six.moves.BaseHTTPServer, select, types, clipboard, console, webbrowser 8 | import urllib 9 | from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler 10 | try: 11 | from cStringIO import StringIO 12 | except ImportError: 13 | from io import StringIO 14 | 15 | from objc_util import * 16 | 17 | SFSafariViewController = ObjCClass('SFSafariViewController') 18 | 19 | global mobile_config_str 20 | mobile_config_str = '' 21 | 22 | global base_mobileconfig 23 | base_mobileconfig = '' 24 | 25 | global keep_running 26 | keep_running = True 27 | 28 | # The Icon key contains a base64 encoded green version of the Pythonista low-res 29 | # icon (for shortness) 30 | 31 | base_mobileconfig = """ 32 | 33 | 34 | PayloadContent 35 | FullScreen 36 | Icon 37 | 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 38 | 39 | IsRemovable 40 | Label%s 41 | PayloadDescriptionConfigures Web Clip 42 | PayloadDisplayNameWeb Clip (Pythonista) 43 | PayloadIdentifierco.hevey.profile.%s 44 | PayloadOrganizationPythonista 45 | PayloadTypecom.apple.webClip.managed 46 | PayloadUUID%s 47 | PayloadVersion1 48 | Precomposed 49 | URLpythonista3://%s?action=run&args=%s 50 | 51 | PayloadDescriptionPythonista Web Clip 52 | PayloadDisplayName%s 53 | PayloadIdentifierco.hevey.profile.%s 54 | PayloadOrganizationPythonista homescreen webclip 55 | PayloadRemovalDisallowed 56 | PayloadTypeConfiguration 57 | PayloadUUID%s 58 | PayloadVersion1 59 | 60 | """ 61 | 62 | class MobileConfigHTTPRequestHandler(SimpleHTTPRequestHandler): 63 | def offer_generic(self): 64 | self.send_response(200) 65 | self.send_header("Content-type", "text/html") 66 | self.send_header("Last-Modified", self.date_time_string()) 67 | self.end_headers() 68 | f = StringIO() 69 | f.write('') 70 | f.write('Something odd happened, click here instead\n') 71 | f.seek(0) 72 | self.wfile.write(bytes(f.getvalue(), 'utf-8')) 73 | #self.copyfile(f, self.wfile) 74 | f.close() 75 | def offer_mobileconfig(self): 76 | global mobile_config_str 77 | if mobile_config_str: 78 | mobileconfig = mobile_config_str 79 | else: 80 | mobileconfig = ' ' 81 | self.send_response(200) 82 | self.send_header("Last-Modified", self.date_time_string()) 83 | self.send_header("Content-type", "application/x-apple-aspen-config") 84 | self.send_header("Content-Length", len(mobileconfig)) 85 | self.end_headers() 86 | f = StringIO() 87 | f.write(mobileconfig) 88 | f.seek(0) 89 | self.wfile.write(bytes(f.getvalue(),'utf-8')) 90 | #self.copyfile(f, self.wfile) 91 | f.close() 92 | global keep_running 93 | keep_running = False 94 | def do_GET(self): 95 | if (self.path.lower().endswith('.mobileconfig')): 96 | return self.offer_mobileconfig() 97 | return self.offer_generic() 98 | 99 | class NicerHTTPServer(six.moves.BaseHTTPServer.HTTPServer): 100 | def serve_forever(self, poll_interval=0.5): 101 | # More limited form of serve forever - shutdown after mobileconfig download 102 | # Works in a single thread 103 | global keep_running 104 | while keep_running: 105 | self._handle_request_noblock() 106 | 107 | def serve_it_up(port, icon_label, arg): 108 | global mobile_config_str 109 | global base_mobileconfig 110 | ip = '127.0.0.1' 111 | icon_label = icon_label # 'Istaflow' 112 | UUID1 = str(uuid.uuid4()).upper() 113 | script_name = 'istaflow/istaflow.py' 114 | arg_str = arg# '%22Show%20Battery%20Details.flow%22' 115 | payload_name = 'Pythonista - %s' % script_name 116 | UUID2 = str(uuid.uuid4()).upper() 117 | mobile_config_str = base_mobileconfig % (icon_label, UUID1, UUID1, script_name, arg_str, payload_name, UUID2, UUID2) 118 | my_httpd = NicerHTTPServer((ip, port), MobileConfigHTTPRequestHandler) 119 | #print("Serving HTTP on %s:%s ..." % (ip,port)) 120 | my_httpd.serve_forever() 121 | #print("\n*** Webclip installed! ***") 122 | 123 | def save(icon_label, flow_name): 124 | port = 8000 125 | flow = '"'+flow_name+'"' 126 | flow = flow.replace('"','%22') 127 | flow = flow.replace(' ','%20') 128 | #urllib.parse.urlencode('"'+flow_name+'"') 129 | 130 | clipboard.set('http://127.0.0.1:%s/webclip.mobileconfig' % port) 131 | console.alert(title='Message', message='If safari doesn\'t open, open Safari and paste url in clipboard to url and install profile',button1='Ok',hide_cancel_button=True) 132 | webbrowser.open('safari-http://127.0.0.1:%s/webclip.mobileconfig' % port) 133 | serve_it_up(port, icon_label, flow) 134 | 135 | -------------------------------------------------------------------------------- /managers/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | -------------------------------------------------------------------------------- /views/AssetPickerView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # original script from https://forum.omz-software.com/topic/2440/asset-picker-in-a-scene/7 3 | 4 | 5 | from __future__ import absolute_import 6 | import os 7 | import json 8 | import ui 9 | import scene 10 | from PIL import Image 11 | 12 | def get_asset_folder(): 13 | try: 14 | p = os.path.dirname(scene.get_image_path('emj:Airplane'))[:-10] 15 | except: 16 | p = os.path.dirname(scene.get_image_path('Airplane'))+'/' 17 | return p 18 | 19 | def get_collection_info(asset_type=''): 20 | folder = get_asset_folder() 21 | try: 22 | with open(folder+os.listdir(folder)[0], 'rt', encoding='utf-8') as f: 23 | return [asset for asset in json.loads(str(f.read()))['collections'] if asset['type'] == asset_type] 24 | except ValueError: 25 | return os.listdir(folder) 26 | 27 | class AssetPicker (ui.View): 28 | def __init__(self, source, selected_cb, name='', dark_cells=False, object_type='none', parent=None, theme_manager= None): 29 | w, h = ui.get_screen_size() 30 | self.frame = (0, 0, w, h) 31 | self.name = name 32 | self.source = source 33 | self.dark_cells = dark_cells 34 | self.parent = parent 35 | self.object_type = object_type 36 | self.picked_asset = None 37 | self.selected_cb = selected_cb 38 | self.theme_manager = theme_manager 39 | self.create_table_view() 40 | 41 | def is_main(self): 42 | return all([1 if isinstance(i, dict) else 0 for i in self.source]) 43 | 44 | def create_table_view(self): 45 | table_view = ui.TableView() 46 | table_view.name = 'tableview' 47 | table_view.flex = 'WH' 48 | table_view.width = self.width 49 | table_view.height = self.height 50 | table_view.delegate = self 51 | table_view.data_source = self 52 | table_view.background_color = self.theme_manager.main_background_colour 53 | 54 | self.add_subview(table_view) 55 | 56 | def tableview_number_of_rows(self, tableview, section): 57 | return len(self.source) 58 | 59 | def tableview_cell_for_row(self, tableview, section, row): 60 | cell = ui.TableViewCell('subtitle') 61 | cell.accessory_type = 'disclosure_indicator' 62 | if self.is_main(): 63 | text = self.source[row]['title'] 64 | cell.text_label.text = text 65 | if 'copyright' in self.source[row]: 66 | cell.detail_text_label.text = self.source[row]['copyright'] 67 | else: 68 | cell.text_label.text = self.source[row] 69 | tableview.row_height = 48 70 | cell.image_view.image = ui.Image.named(self.source[row]) 71 | if self.dark_cells: 72 | cell.image_view.background_color = 'black' 73 | cell.text_label.text_color = self.theme_manager.main_text_colour 74 | cell.detail_text_label.text_color = self.theme_manager.main_text_colour 75 | cell.background_color = self.theme_manager.main_background_colour 76 | return cell 77 | 78 | def tableview_did_select(self, tableview, section, row): 79 | if not self.is_main(): 80 | if self.parent: 81 | pass 82 | # do something with asset 83 | # example: 84 | self.selected_cb(self.source[row]) 85 | self.navigation_view.pop_view() 86 | return 87 | path = os.path.join(get_asset_folder(), self.source[row]['path']) 88 | if not os.path.isdir(path): 89 | with open(path, 'r') as f: 90 | source = eval(f.read()) 91 | else: 92 | source = sorted(list(set([path.split('/')[-1]+':'+(i.split('@')[0] if '@' in i else i.split('.')[0]) for i in os.listdir(path)]))) 93 | dark_cells = 1 if 'darkBackground' in self.source[row] else 0 94 | self.navigation_view.push_view(AssetPicker(source, name=self.source[row]['title'], dark_cells=dark_cells, object_type=self.object_type, parent=self.parent, selected_cb=self.selected_cb, theme_manager = self.theme_manager)) 95 | 96 | def get_view(selected_cb, parent=None, object_type='none', theme_manager=None): 97 | source = get_collection_info(asset_type='image') 98 | main_view = AssetPicker(source, name='Assets', object_type=object_type, parent=parent, selected_cb=selected_cb, theme_manager=theme_manager) 99 | main_view.background_color = theme_manager.main_background_colour 100 | return main_view 101 | 102 | if __name__ == '__main__': 103 | v= get_view(None) 104 | v.present() 105 | 106 | 107 | -------------------------------------------------------------------------------- /views/ElementCreationView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | import ui 5 | import console 6 | from . import AssetPickerView 7 | 8 | dbo = None 9 | class ElementCreationView(object): 10 | def __init__(self, saveCallBack, showAssetPickerCallBack, closeAssetPickerCallBack, thememanager): 11 | self.saveCallBack = saveCallBack 12 | self.numberOfRows = 7 13 | self.titleRow = 0 14 | self.inputTypeRow = 1 15 | self.outputTypeRow = 2 16 | self.descriptionRow = 3 17 | self.iconRow = 4 18 | self.categoryRow = 5 19 | self.canHandleListRow = 6 20 | self.title = '' 21 | self.inputType = None 22 | self.outputType = None 23 | self.description = '' 24 | self.icon = '' 25 | self.category = '' 26 | self.canHandleList = False 27 | self.showAssetPickerCallBack = showAssetPickerCallBack 28 | self.closeAssetPickerCallBack = closeAssetPickerCallBack 29 | self.assetPickerView = AssetPickerView.get_view(self.set_iconcb, theme_manager = thememanager) 30 | self.thememanager = thememanager 31 | 32 | def reset_view(self): 33 | self.title = '' 34 | self.inputType = None 35 | self.outputType = None 36 | self.description = '' 37 | self.icon = '' 38 | self.category = '' 39 | 40 | def tableview_did_select(self, tableview, section, row): 41 | if row == self.titleRow: 42 | self.change_title() 43 | elif row == self.inputTypeRow: 44 | self.change_input_type() 45 | elif row == self.outputTypeRow: 46 | self.change_output_type() 47 | elif row == self.descriptionRow: 48 | self.change_description() 49 | elif row == self.iconRow: 50 | self.change_icon() 51 | elif row == self.categoryRow: 52 | self.change_category() 53 | 54 | def tableview_title_for_header(self, tableview, section): 55 | pass 56 | 57 | def tableview_number_of_sections(self, tableview): 58 | return 1 59 | 60 | def tableview_number_of_rows(self, tableview, section): 61 | return self.numberOfRows 62 | 63 | def tableview_cell_for_row(self, tableview, section, row): 64 | cell = ui.TableViewCell('value1') 65 | if row == self.titleRow: 66 | cell.text_label.text = 'Title' 67 | if self.title.strip(' ') == '': 68 | cell.detail_text_label.text = 'Please enter a title' 69 | else: 70 | cell.detail_text_label.text = self.title 71 | elif row == self.inputTypeRow: 72 | cell.text_label.text = 'Input Type' 73 | if self.inputType == None: 74 | cell.detail_text_label.text = 'None' 75 | else: 76 | cell.detail_text_label.text = self.inputType 77 | elif row == self.outputTypeRow: 78 | cell.text_label.text = 'Output Type' 79 | if self.outputType == None: 80 | cell.detail_text_label.text = 'None' 81 | else: 82 | cell.detail_text_label.text = self.outputType 83 | elif row == self.descriptionRow: 84 | cell.text_label.text = 'Description' 85 | if self.description.strip(' ') == '': 86 | cell.detail_text_label.text = 'Please enter a description' 87 | else: 88 | cell.detail_text_label.text = self.description 89 | elif row == self.iconRow: 90 | cell.text_label.text = 'Icon' 91 | if self.icon.strip(' ') == '': 92 | cell.detail_text_label.text = 'Please choose a icon' 93 | else: 94 | cell.detail_text_label.text = self.icon 95 | elif row == self.categoryRow: 96 | cell.text_label.text = 'Category' 97 | if self.category.strip(' ') == '': 98 | cell.detail_text_label.text = 'Please enter a category' 99 | else: 100 | cell.detail_text_label.text = self.category 101 | elif row == self.canHandleListRow: 102 | cell.text_label.text = 'Can Handle List' 103 | cell.selectable = False 104 | switch = ui.Switch() 105 | switch.name = 'canHandleList' 106 | switch.value = False 107 | switch.y = cell.center.y - switch.height/2 108 | switch.x = cell.width + switch.width/2 109 | switch.action = self.canHandleListAction 110 | cell.add_subview(switch) 111 | cell.text_label.text_color = self.thememanager.main_text_colour 112 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 113 | cell.background_color = self.thememanager.main_background_colour 114 | return cell 115 | 116 | def canHandleListAction(self, sender): 117 | self.canHandleList = sender.value 118 | 119 | @ui.in_background 120 | def change_title(self): 121 | self.title = console.input_alert(title='Enter Element title', message='Space in title will be removed for filename and classname. If element with file exists it will be overwritten without warning.') 122 | table_view.reload() 123 | 124 | @ui.in_background 125 | def change_input_type(self): 126 | self.inputType = console.input_alert(title='Enter Element Input type', message='Enter input type, enter an empty string for None') 127 | if self.inputType.strip(' ') == '': 128 | self.inputType = None 129 | table_view.reload() 130 | 131 | @ui.in_background 132 | def change_output_type(self): 133 | self.outputType = console.input_alert(title='Enter Element Output type', message='Enter output type, enter an empty string for None') 134 | if self.outputType.strip(' ') == '': 135 | self.outputType = None 136 | table_view.reload() 137 | 138 | @ui.in_background 139 | def change_description(self): 140 | self.description = console.input_alert(title='Enter Element Description', message='Enter a description for the element') 141 | table_view.reload() 142 | 143 | def set_iconcb(self, icon): 144 | self.icon = icon 145 | self.closeAssetPickerCallBack(self.assetPickerView) 146 | table_view.reload() 147 | 148 | @ui.in_background 149 | def change_icon(self): 150 | self.showAssetPickerCallBack(self.assetPickerView) 151 | 152 | @ui.in_background 153 | def change_category(self): 154 | self.category = console.input_alert(title='Enter Element Category', message='Enter the Element category, this is required') 155 | if self.category.strip(' ') == '': 156 | self.category = None 157 | table_view.reload() 158 | 159 | def create_element(self, sender): 160 | valid = True 161 | if self.title.strip(' ') == '': 162 | valid = False 163 | 164 | if valid: 165 | self.saveCallBack(title=self.title, inputType=self.inputType, outputType=self.outputType, description=self.description, icon=self.icon, category=self.category, canHandleList=self.canHandleList) 166 | self.reset_view() 167 | else: 168 | console.hud_alert('Invalid') 169 | 170 | table_view = ui.TableView() 171 | def get_view(savecb, apcb, capcb, thememanager): 172 | dbo = ElementCreationView(saveCallBack = savecb, showAssetPickerCallBack = apcb, closeAssetPickerCallBack = capcb, thememanager = thememanager) 173 | table_view.name = 'Element' 174 | table_view.data_source = dbo 175 | table_view.delegate = dbo 176 | table_view.right_button_items = [ui.ButtonItem(title='Save Element', action=dbo.create_element)] 177 | table_view.background_color = thememanager.main_background_colour 178 | return table_view 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /views/ElementListView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | import ui 5 | import copy 6 | class ElementListView(object): 7 | def __init__(self, elements, selectedCallBack, thememanager): 8 | self.elements = elements 9 | self.scb = selectedCallBack 10 | self.thememanager = thememanager 11 | if 'Dont Display' in self.elements.keys(): 12 | del self.elements['Dont Display'] 13 | 14 | def tableview_did_select(self, tableview, section, row): 15 | section_key = list(self.elements.keys())[section] 16 | self.scb(copy.deepcopy(self.elements[section_key][row])) 17 | 18 | def tableview_title_for_header(self, tableview, section): 19 | return list(self.elements.keys())[section] 20 | 21 | def tableview_number_of_sections(self, tableview): 22 | return len(self.elements) 23 | 24 | def tableview_number_of_rows(self, tableview, section): 25 | return len(self.elements[list(self.elements.keys())[section]]) 26 | 27 | def tableview_cell_for_row(self, tableview, section, row): 28 | section_key = list(self.elements.keys())[section] 29 | try: 30 | cell = ui.TableViewCell('subtitle') 31 | cell.background_color = self.thememanager.main_background_colour 32 | cell.text_label.text_color = self.thememanager.main_text_colour 33 | cell.text_label.text = self.elements[section_key][row].get_title() 34 | cell.detail_text_label.text = self.elements[section_key][row].get_description() 35 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 36 | cell.image_view.image = ui.Image.named(self.elements[section_key][row].get_icon()) 37 | cell.selectable = True 38 | return cell 39 | except: 40 | cell = ui.TableViewCell('subtitle') 41 | cell.text_label.text = self.elements[section_key][row].get_title() 42 | cell.detail_text_label.text = 'Is invalid please check file in elements folder' 43 | cell.selectable = False 44 | return cell 45 | 46 | def get_view(elements, cb, thememanager): 47 | dbo = ElementListView(elements = elements, selectedCallBack = cb, thememanager = thememanager) 48 | table_view = ui.TableView() 49 | table_view.name = 'Elements' 50 | table_view.data_source = dbo 51 | table_view.delegate = dbo 52 | table_view.background_color = thememanager.main_background_colour 53 | return table_view 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /views/ElementManagementView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | import ui 5 | 6 | class ElementManagementView(object): 7 | def __init__(self, elements, thememanager): 8 | self.elements = elements 9 | self.thememanager = thememanager 10 | 11 | def tableview_did_select(self, tableview, section, row): 12 | pass 13 | 14 | def tableview_title_for_header(self, tableview, section): 15 | return list(self.elements.keys())[section] 16 | 17 | def tableview_number_of_sections(self, tableview): 18 | return len(self.elements) 19 | 20 | def tableview_number_of_rows(self, tableview, section): 21 | return len(self.elements[list(self.elements.keys())[section]]) 22 | 23 | def tableview_cell_for_row(self, tableview, section, row): 24 | section_key = list(self.elements.keys())[section] 25 | try: 26 | cell = ui.TableViewCell('subtitle') 27 | cell.text_label.text = self.elements[section_key][row].get_title() 28 | cell.detail_text_label.text = self.elements[section_key][row].get_description() 29 | cell.image_view.image = ui.Image.named(self.elements[section_key][row].get_icon()) 30 | cell.selectable = False 31 | cell.background_color = self.thememanager.main_background_colour 32 | cell.text_label.text_color = self.thememanager.main_text_colour 33 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 34 | return cell 35 | except: 36 | cell = ui.TableViewCell('subtitle') 37 | cell.text_label.text = self.elements[section_key][row].get_title() 38 | cell.detail_text_label.text = 'Is invalid please check file in elements folder' 39 | cell.selectable = False 40 | return cell 41 | 42 | def get_view(elements, thememanager): 43 | dbo = ElementManagementView(elements = elements, thememanager = thememanager) 44 | table_view = ui.TableView() 45 | table_view.name = 'Elements' 46 | table_view.data_source = dbo 47 | table_view.delegate = dbo 48 | table_view.background_color = thememanager.main_background_colour 49 | return table_view 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /views/ElementParameterDictionaryInputView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # coding: utf-8 3 | 4 | from __future__ import absolute_import 5 | import ui 6 | import dialogs 7 | 8 | class ElementParameterDictionaryInputView(object): 9 | def __init__(self): 10 | self.dictionary = {} 11 | self.thememanager = None 12 | 13 | def tableview_did_select(self, tableview, section, row): 14 | key = list(self.dictionary.keys())[row] 15 | value = self.dictionary[key] 16 | edit_item(key, value) 17 | 18 | def tableview_title_for_header(self, tableview, section): 19 | pass 20 | 21 | def tableview_number_of_sections(self, tableview): 22 | return 1 23 | 24 | def tableview_number_of_rows(self, tableview, section): 25 | return len(list(self.dictionary.keys())) 26 | 27 | def tableview_cell_for_row(self, tableview, section, row): 28 | cell = ui.TableViewCell('value1') 29 | key = list(self.dictionary.keys())[row] 30 | cell.text_label.text = key 31 | cell.detail_text_label.text = self.dictionary[key] 32 | cell.background_color = self.thememanager.main_background_colour 33 | cell.text_label.text_color = self.thememanager.main_text_colour 34 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 35 | cell.selectable = True 36 | return cell 37 | 38 | def tableview_can_delete(self, tableview, section, row): 39 | return True 40 | 41 | def tableview_delete(self, tableview, section, row): 42 | # Called when the user confirms deletion of the given row. 43 | key = list(self.dictionary.keys())[row] 44 | self.dictionary.pop(key) 45 | del_row([row]) 46 | 47 | table_view = ui.TableView() 48 | dbo = ElementParameterDictionaryInputView() 49 | def get_view(thememanager, dictionary={}, title='Dictionary', cb=None): 50 | dicti = dictionary 51 | if dicti == None: 52 | dicti = {} 53 | dbo.dictionary=dicti 54 | dbo.thememanager = thememanager 55 | table_view.name = title 56 | table_view.data_source = dbo 57 | table_view.delegate = dbo 58 | table_view.right_button_items = [ui.ButtonItem(title='Add', action = add_item), ui.ButtonItem(title='Save', action=cb)] 59 | table_view.background_color=thememanager.main_background_colour 60 | return table_view 61 | 62 | @ui.in_background 63 | def edit_item(key, value): 64 | values = dialogs.form_dialog(title='Edit Item', fields=[{'type':'text', 'title':'Key', 'value':key},{'type':'text', 'title':'Value', 'value':value}]) 65 | if not values == None: 66 | dbo.dictionary[values['Key']] = values['Value'] 67 | table_view.reload() 68 | 69 | def add_item(sender): 70 | values = dialogs.form_dialog(title='Add Item', fields=[{'type':'text', 'title':'Key'},{'type':'text', 'title':'Value'}]) 71 | if not values == None: 72 | dbo.dictionary[values['Key']] = values['Value'] 73 | table_view.reload() 74 | 75 | def del_row(row): 76 | table_view.delete_rows(row) 77 | 78 | 79 | -------------------------------------------------------------------------------- /views/ElementRuntimeView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | import ui 5 | import console 6 | import dialogs 7 | from . import ElementParameterDictionaryInputView 8 | 9 | class ElementRuntimeView (object): 10 | def __init__(self, thememanager): 11 | self.element = None 12 | self.params = [] 13 | self.dictionaryParam = None 14 | self.tv = None 15 | self.dictView = None 16 | self.thememanager = thememanager 17 | 18 | @ui.in_background 19 | def tableview_did_select(self, tableview, section, row): 20 | param = self.params[row] 21 | name = param.displayName 22 | value = param.value 23 | noVariable = True 24 | if param.isVariableAllowed: 25 | choice = console.alert(title='Variable Available', message = 'Would you like to choose a variable?', button1='Choose Variable', button2 = 'Ask when run', button3='Don\'t use a variable') 26 | if choice == 1: 27 | noVariable = False 28 | param.useVariable = True 29 | param.variableName = console.input_alert(title='Option',message='Please enter the variable name') 30 | param.value = None 31 | param.askAtRuntime = False 32 | elif choice == 2: 33 | noVariable = False 34 | param.useVariable = True 35 | param.value = None 36 | param.askAtRuntime = True 37 | param.variableName='' 38 | else: 39 | noVariable = True 40 | param.useVariable = False 41 | param.askAtRuntime = False 42 | param.variableName = '' 43 | if name == None or name == '': 44 | name = param.name 45 | if value == None: 46 | value = '' 47 | if noVariable and param.type == 'string': 48 | param.value = console.input_alert(name, '', value) 49 | elif noVariable and param.type == 'int': 50 | param.value = int(console.input_alert(name,'',str(value))) 51 | elif noVariable and param.type == 'variable': 52 | pass 53 | elif noVariable and param.type == 'list': 54 | ret = dialogs.list_dialog(title=name,items=param.allowedValues, multiple=param.multipleAllowed) 55 | yo = '' 56 | if not ret == None: 57 | if isinstance(ret,list): 58 | for item in ret: 59 | yo += item+',' 60 | else: 61 | yo = ret 62 | yo = yo.rstrip(',') 63 | param.value = yo 64 | elif noVariable and param.type == 'dictionary': 65 | self.dictionaryParam = param 66 | self.dictView = ElementParameterDictionaryInputView.get_view(dictionary=param.value, title=name, cb=self.dictionaryReturn, thememanager = self.thememanager) 67 | self.tv = tableview 68 | self.dictView.title_bar_color = self.thememanager.main_bar_colour 69 | self.dictView.tint_color = self.thememanager.main_tint_colour 70 | self.dictView.present(orientations=['portrait']) 71 | elif noVariable and param.type == 'Boolean': 72 | pass 73 | tableview.reload() 74 | 75 | def dictionaryReturn(self, sender): 76 | self.dictionaryParam.value = self.dictView.data_source.dictionary 77 | self.dictView.close() 78 | self.tv.reload() 79 | 80 | 81 | def tableview_title_for_header(self, tableview, section): 82 | return 'Parameters' 83 | 84 | def tableview_number_of_sections(self, tableview): 85 | return 1 86 | 87 | def tableview_number_of_rows(self, tableview, section): 88 | return len(self.params) 89 | 90 | def tableview_cell_for_row(self, tableview, section, row): 91 | param = self.params[row] 92 | name = param.displayName 93 | cell = None 94 | if name == None or name == '': 95 | name = param.name 96 | if param.type == 'bool': 97 | cell = ui.TableViewCell() 98 | cell.selectable = False 99 | switch = ui.Switch() 100 | switch.name = param.name 101 | switch.value = param.value 102 | switch.y = cell.center.y - switch.height/2 103 | switch.x = cell.width + switch.width/2 104 | switch.action = self.switch_change 105 | cell.add_subview(switch) 106 | elif param.type == 'slider': 107 | cell = ui.TableViewCell() 108 | cell.selectable = False 109 | slider = ui.Slider() 110 | slider.name = param.name 111 | slider.value = param.value 112 | slider.y = cell.center.y - slider.height/2 113 | slider.x = cell.width-15 114 | slider.action = self.switch_change 115 | cell.add_subview(slider) 116 | else: 117 | cell = ui.TableViewCell('value1') 118 | if param.useVariable: 119 | if not param.variableName == None and not param.variableName == '': 120 | cell.detail_text_label.text = 'Variable: ' + str(param.variableName) 121 | else: 122 | cell.detail_text_label.text = 'Variable: Choose at runtime' 123 | elif not param.value == None: 124 | cell.detail_text_label.text = str(param.value) 125 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 126 | 127 | 128 | cell.text_label.text = name 129 | cell.background_color = self.thememanager.main_background_colour 130 | cell.text_label.text_color = self.thememanager.main_text_colour 131 | 132 | return cell 133 | 134 | def tableview_can_delete(self, tableview, section, row): 135 | return False 136 | 137 | def tableview_can_move(self, tableview, section, row): 138 | return False 139 | 140 | def tableview_delete(self, tableview, section, row): 141 | pass 142 | 143 | def tableview_move_row(self, tableview, from_section, from_row, to_section, to_row): 144 | pass 145 | 146 | def load_element(self, element): 147 | self.element = element 148 | self.params = [] 149 | for param in element.get_params(): 150 | if param.display: 151 | self.params.append(param) 152 | 153 | def switch_change(self, sender): 154 | for p in self.params: 155 | if p.name == sender.name: 156 | p.value = sender.value 157 | 158 | 159 | table_view = ui.TableView() 160 | def get_view(thememanager): 161 | dbo = ElementRuntimeView(thememanager=thememanager) 162 | table_view.name = 'Element' 163 | table_view.data_source = dbo 164 | table_view.delegate = dbo 165 | table_view.background_color = thememanager.main_background_colour 166 | return table_view 167 | 168 | 169 | -------------------------------------------------------------------------------- /views/FlowCreationView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | import ui 5 | import console 6 | import clipboard 7 | dbo = None 8 | 9 | class FlowCreationView(object): 10 | def __init__(self, elements, saveCallBack, addElementAction, saveFlowAction, runFlowAction, showElementRuntimeView, thememanager, flowType, flowTypeSelection, saveToHomeScreenAction, copyFlowToClipboardCallBack): 11 | self.flowType = flowType 12 | self.elements = elements 13 | self.saveCallBack = saveCallBack 14 | self.safeFlowAction = saveFlowAction 15 | self.flowTypeSelection = flowTypeSelection 16 | self.showElementRuntimeView = showElementRuntimeView 17 | self.extraRows = 5 18 | self.adminRow = 0 19 | self.saveToHomeScreenRow = 3 20 | self.typeRow = 2 21 | self.titleRow = 1 22 | self.shareRow = 4 23 | self.title = '' 24 | self.oldtitle = '' 25 | self.currentElementNumber = -1 26 | self.addElementButton = ui.ButtonItem(title = 'Add Element', action = addElementAction) 27 | self.saveFlowButton = ui.Button(title='Save') 28 | self.runFlowButton = ui.ButtonItem(title='Run', action=runFlowAction) 29 | self.saveToHomeScreenAction = saveToHomeScreenAction 30 | self.editButtonsRight = [self.addElementButton] 31 | self.editButtonsLeft = [] 32 | self.runButtonsRight = [self.runFlowButton] 33 | self.runButtonsLeft = [] 34 | self.thememanager = thememanager 35 | self.copyFlowToClipboardCallBack = copyFlowToClipboardCallBack 36 | 37 | def update_buttons(self): 38 | if table_view.editing: 39 | show_edit_buttons() 40 | else: 41 | show_run_buttons() 42 | 43 | def tableview_did_select(self, tableview, section, row): 44 | if section == 0: 45 | if row == self.typeRow: 46 | self.flowTypeSelection() 47 | elif row == self.saveToHomeScreenRow: 48 | self.saveToHomeScreenAction() 49 | elif row == self.titleRow: 50 | self.change_title() 51 | elif row == self.shareRow: 52 | self.shareFlow() 53 | elif section == 1: 54 | element = self.elements[row] 55 | params = element.get_params() or [] 56 | show = any(p.display for p in params) 57 | if show: 58 | self.showElementRuntimeView(element) 59 | 60 | def tableview_title_for_header(self, tableview, section): 61 | if section == 1: 62 | return 'Elements' 63 | 64 | def tableview_number_of_sections(self, tableview): 65 | return 2 66 | 67 | def tableview_number_of_rows(self, tableview, section): 68 | if section == 0: 69 | return self.extraRows 70 | elif section == 1: 71 | return len(self.elements) 72 | 73 | def tableview_cell_for_row(self, tableview, section, row): 74 | #if row >= self.extraRows: 75 | if section == 1: 76 | element = self.elements[row] 77 | cell = ui.TableViewCell('subtitle') 78 | cell.selectable = False 79 | cell.text_label.text = element.get_title() 80 | cell.detail_text_label.text = element.get_description() 81 | cell.background_color=self.thememanager.main_background_colour 82 | cell.image_view.image = ui.Image.named(element.get_icon()) 83 | params = element.get_params() or [] 84 | selectable = False 85 | for p in params: 86 | if p.display: 87 | selectable = True 88 | cell.accessory_type = 'disclosure_indicator' 89 | cell.selectable = selectable 90 | if self.currentElementNumber >= self.extraRows: 91 | cell.selectable = False 92 | if self.currentElementNumber+(-1)== row: 93 | cell.background_color = self.thememanager.running_cell_background_colour 94 | cell.text_label.text_color = self.thememanager.running_cell_text_colour 95 | cell.detail_text_label.text_color = self.thememanager.running_cell_text_colour 96 | else: 97 | cell.background_color = self.thememanager.main_background_colour 98 | cell.text_label.text_color = self.thememanager.main_text_colour 99 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 100 | return cell 101 | elif section == 0: 102 | if row == self.adminRow: 103 | cell = ui.TableViewCell() 104 | cell.background_color=self.thememanager.main_background_colour 105 | cell.selectable = False 106 | editButton = ui.Button(title='Done' if tableview.editing else 'Edit') 107 | editButton.width *= 1.4 108 | editButton.action = swap_edit 109 | editButton.y = cell.height/2 - editButton.height/2 110 | editButton.x = ui.get_screen_size()[0]-(editButton.width*1.5) 111 | cell.add_subview(editButton) 112 | self.saveFlowButton.y = cell.height/2 - self.saveFlowButton.height/2 113 | self.saveFlowButton.x = self.saveFlowButton.width 114 | self.saveFlowButton.action = self.safeFlowAction 115 | cell.add_subview(self.saveFlowButton) 116 | return cell 117 | elif row == self.saveToHomeScreenRow: 118 | cell = ui.TableViewCell() 119 | cell.background_color=self.thememanager.main_background_colour 120 | cell.selectable = True 121 | cell.text_label.text_color = self.thememanager.main_text_colour 122 | cell.text_label.text = 'Save To Home Screen' 123 | return cell 124 | elif row == self.typeRow: 125 | cell = ui.TableViewCell('value1') 126 | cell.background_color=self.thememanager.main_background_colour 127 | cell.selectable = True 128 | cell.text_label.text_color = self.thememanager.main_text_colour 129 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 130 | cell.text_label.text = 'Type of Flow' 131 | cell.detail_text_label.text = self.flowType 132 | return cell 133 | elif row == self.titleRow: 134 | cell = ui.TableViewCell('value1') 135 | cell.background_color=self.thememanager.main_background_colour 136 | cell.selectable = True 137 | cell.text_label.text_color = self.thememanager.main_text_colour 138 | cell.detail_text_label.text_color = self.thememanager.main_text_colour 139 | cell.text_label.text = 'Flow Title' 140 | cell.detail_text_label.text = self.title 141 | return cell 142 | elif row == self.shareRow: 143 | cell = ui.TableViewCell() 144 | cell.background_color=self.thememanager.main_background_colour 145 | cell.selectable = True 146 | cell.text_label.text_color = self.thememanager.main_text_colour 147 | cell.text_label.text = 'Share Flow' 148 | return cell 149 | 150 | @ui.in_background 151 | def change_title(self): 152 | self.oldtitle = self.title 153 | self.title = console.input_alert('Flow title','',self.title,'Ok',False) 154 | table_view.name = self.title 155 | table_view.reload() 156 | 157 | 158 | def tableview_can_delete(self, tableview, section, row): 159 | # Return True if the user should be able to delete the given row. 160 | if section == 0: 161 | return False 162 | elif section == 1: 163 | return True 164 | 165 | def tableview_can_move(self, tableview, section, row): 166 | # Return True if a reordering control should be shown for the given row (in editing mode). 167 | if section == 0: 168 | return False 169 | elif section == 1: 170 | return True 171 | 172 | def tableview_delete(self, tableview, section, row): 173 | # Called when the user confirms deletion of the given row. 174 | if section == 1: 175 | print(section + row) 176 | self.elements.pop(row) 177 | del_row([(row,section)]) 178 | 179 | def tableview_move_row(self, tableview, from_section, from_row, to_section, to_row): 180 | to = to_row 181 | if from_section > to_section: 182 | to = 0 183 | self.elements.insert(to, self.elements.pop(from_row)) 184 | tableview.reload() 185 | 186 | @ui.in_background 187 | def shareFlow(self): 188 | option = console.alert(title='Share',message='How would you like to share the flow?', button1='Copy to Clipboard') 189 | if option == 1: 190 | self.copyFlowToClipboardCallBack() 191 | 192 | table_view = ui.TableView() 193 | 194 | def get_view(elements, saveCallBack, addElementAction, saveFlowAction, runFlowAction, showElementRuntimeView,thememanager, flowType, flowTypeSelection, saveToHomeScreenAction, copyFlowToClipboardCallBack): 195 | dbo = FlowCreationView(elements = elements, saveCallBack = saveCallBack, addElementAction = addElementAction, saveFlowAction = saveFlowAction, runFlowAction = runFlowAction, showElementRuntimeView = showElementRuntimeView, thememanager=thememanager, flowType=flowType, flowTypeSelection=flowTypeSelection, saveToHomeScreenAction=saveToHomeScreenAction, copyFlowToClipboardCallBack = copyFlowToClipboardCallBack) 196 | table_view.name = 'Flow' 197 | table_view.background_color = thememanager.main_background_colour 198 | table_view.data_source = dbo 199 | table_view.delegate = dbo 200 | show_run_buttons() 201 | return table_view 202 | 203 | def swap_edit(sender): 204 | if table_view.editing: 205 | table_view.editing = False 206 | sender.title = 'Edit' 207 | show_run_buttons() 208 | else: 209 | table_view.editing = True 210 | sender.title = 'Done' 211 | show_edit_buttons() 212 | table_view.reload() 213 | 214 | def show_edit_buttons(): 215 | table_view.right_button_items = table_view.data_source.editButtonsRight 216 | table_view.left_button_items = table_view.data_source.editButtonsLeft 217 | 218 | def show_run_buttons(): 219 | if table_view.data_source.elements: 220 | table_view.right_button_items = table_view.data_source.runButtonsRight 221 | else: 222 | table_view.right_button_items = [] 223 | table_view.left_button_items = table_view.data_source.runButtonsLeft 224 | 225 | def del_row(row): 226 | table_view.delete_rows(row) 227 | 228 | 229 | -------------------------------------------------------------------------------- /views/FlowsView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | import ui 5 | 6 | class FlowsView(object): 7 | def __init__(self, flows, flowselectedcb, flowdeletedcb, thememanager): 8 | self.flows = flows or [] 9 | self.flowselectedcb = flowselectedcb 10 | self.flowdeletedcb = flowdeletedcb 11 | self.thememanager = thememanager 12 | 13 | def tableview_did_select(self, tableview, section, row): 14 | self.flowselectedcb(self.flows[row]) 15 | 16 | def tableview_title_for_header(self, tableview, section): 17 | pass 18 | 19 | def tableview_number_of_sections(self, tableview): 20 | return 1 21 | 22 | def tableview_number_of_rows(self, tableview, section): 23 | return len(self.flows) 24 | 25 | def tableview_cell_for_row(self, tableview, section, row): 26 | cell = ui.TableViewCell() 27 | cell.text_label.text = self.flows[row] 28 | cell.background_color = self.thememanager.main_background_colour 29 | cell.text_label.text_color = self.thememanager.main_text_colour 30 | cell.selectable = True 31 | return cell 32 | 33 | def tableview_can_delete(self, tableview, section, row): 34 | # Return True if the user should be able to delete the given row. 35 | return True 36 | 37 | def tableview_can_move(self, tableview, section, row): 38 | # Return True if a reordering control should be shown for the given row (in editing mode). 39 | return True 40 | 41 | def tableview_delete(self, tableview, section, row): 42 | # Called when the user confirms deletion of the given row. 43 | self.flowdeletedcb(self.flows[row]) 44 | self.flows.pop(row) 45 | table_view.delete_rows([row]) 46 | 47 | def tableview_move_row(self, tableview, from_section, from_row, to_section, to_row): 48 | # Called when the user moves a row with the reordering control (in editing mode). 49 | pass 50 | 51 | table_view = ui.TableView() 52 | def get_view(flows, selectedcb, deletedcb, thememanager): 53 | dbo = FlowsView(flows = flows, flowselectedcb = selectedcb, flowdeletedcb = deletedcb, thememanager=thememanager) 54 | table_view.name = 'Flows' 55 | table_view.background_color=thememanager.main_background_colour 56 | table_view.data_source = dbo 57 | table_view.delegate = dbo 58 | return table_view 59 | 60 | 61 | -------------------------------------------------------------------------------- /views/MapView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # This has been derived for mapview example by Ole Zorn @omz url to come soon 3 | 4 | from __future__ import absolute_import 5 | import ui 6 | from objc_util import * 7 | import location 8 | 9 | class CLLocationCoordinate2D (Structure): 10 | _fields_ = [('latitude', c_double), ('longitude', c_double)] 11 | 12 | class MapView (ui.View): 13 | @on_main_thread 14 | def __init__(self, *args, **kwargs): 15 | ui.View.__init__(self, *args, **kwargs) 16 | MKMapView = ObjCClass('MKMapView') 17 | frame = CGRect(CGPoint(0, 0), CGSize(self.width, self.height)) 18 | self.mk_map_view = MKMapView.alloc().initWithFrame_(frame) 19 | flex_width, flex_height = (1<<1), (1<<4) 20 | self.mk_map_view.setAutoresizingMask_(flex_width|flex_height) 21 | self_objc = ObjCInstance(self) 22 | self_objc.addSubview_(self.mk_map_view) 23 | self.mk_map_view.release() 24 | 25 | @on_main_thread 26 | def add_pin(self, lat, lon, title, subtitle=None, select=False): 27 | '''Add a pin annotation to the map''' 28 | MKPointAnnotation = ObjCClass('MKPointAnnotation') 29 | coord = CLLocationCoordinate2D(lat, lon) 30 | annotation = MKPointAnnotation.alloc().init().autorelease() 31 | annotation.setTitle_(title) 32 | if subtitle: 33 | annotation.setSubtitle_(subtitle) 34 | annotation.setCoordinate_(coord, restype=None, argtypes=[CLLocationCoordinate2D]) 35 | self.mk_map_view.addAnnotation_(annotation) 36 | if select: 37 | self.mk_map_view.selectAnnotation_animated_(annotation, True) 38 | 39 | @on_main_thread 40 | def remove_all_pins(self): 41 | '''Remove all annotations (pins) from the map''' 42 | self.mk_map_view.removeAnnotations_(self.mk_map_view.annotations()) 43 | 44 | if __name__ == '__main__': 45 | m = MapView() 46 | location.start_updates() 47 | loc = location.get_location() 48 | location.stop_updates() 49 | m.add_pin(lat = loc['latitude'], lon = loc['longitude'],title='Test') 50 | m.mk_map_view.setShowsUserLocation_(True) 51 | m.present() 52 | 53 | 54 | -------------------------------------------------------------------------------- /views/ToastView.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # author: Shaun Hevey 3 | # toast.py is the implementation of a android inspired toast for pythonista. 4 | 5 | 6 | from __future__ import absolute_import 7 | import ui 8 | import time 9 | def display_toast(view, help_text, width = 220, height = 110, show_duration=2, fade_duration=0.5, background_colour=(.42, .42, .42), text_colour= (.96, .96, .96), corner_radius=10): 10 | 11 | w, h = ui.get_screen_size() 12 | 13 | help_view = ui.View(frame=((w/2)-(width/2),(h/2)-height, width, height)) 14 | help_view.background_color = background_colour 15 | help_view.corner_radius = corner_radius 16 | 17 | label = ui.Label() 18 | label.text = help_text 19 | label.flex = 'H' 20 | label.width = help_view.width * 0.9 21 | label.alignment = ui.ALIGN_CENTER 22 | label.x = (help_view.width / 2) - (label.width / 2) 23 | label.y = (help_view.height / 2) - (label.height / 2) 24 | label.number_of_lines = 3 25 | 26 | label.text_color = text_colour 27 | 28 | help_view.add_subview(label) 29 | 30 | def animation_fade_in(): 31 | help_view.alpha = 1.0 32 | def animation_fade_out(): 33 | help_view.alpha = 0.0 34 | 35 | help_view.alpha = 0.0 36 | view.add_subview(help_view) 37 | ui.animate(animation_fade_in, duration=fade_duration) 38 | time.sleep(show_duration+fade_duration) 39 | ui.animate(animation_fade_out, duration=fade_duration) 40 | time.sleep(fade_duration) 41 | view.remove_subview(help_view) 42 | 43 | if __name__=='__main__': 44 | view = ui.View() 45 | view.flex = 'WH' 46 | view.background_color = (1.0, 1.0, 1.0) 47 | view.present() 48 | display_toast(view=view, help_text='Show me a toast in pythonista') 49 | 50 | 51 | -------------------------------------------------------------------------------- /views/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | --------------------------------------------------------------------------------