Swift UI animated closure - swiftui

If I have a SwiftUI view declaration like:
ProfileView(userData, onDoneEdit: {
withAnimation {
isEditingViewPresented.toggle()
}
...
}, onCancel: { ... })
does anyone know if it can be implemented a custom annotation that let me have:
ProfileView(userData, onDoneEdit: { #withAnimation
isEditingViewPresented.toggle()
...
}, onCancel: { ... })
This question is more for learning purpose as I'm experimenting with SwiftUI.

Related

How to change the label of a Menu?

In a simple test project at Github I am trying to display a Menu with 3 languages and the flags to allow users select the localization:
struct ContentView: View {
// ...some Core Data related code skipped...
let labels = [
"en" : "πŸ‡ΊπŸ‡Έ EN",
"de" : "πŸ‡©πŸ‡ͺ DE",
"ru" : "πŸ‡·πŸ‡Ί RU"
]
#AppStorage("language") var language:String = "en"
var body: some View {
VStack(alignment: .trailing) {
Menu(language) {
Button("πŸ‡ΊπŸ‡Έ EN", action: { language = "en" })
Button("πŸ‡©πŸ‡ͺ DE", action: { language = "de" })
Button("πŸ‡·πŸ‡Ί RU", action: { language = "ru" })
}.padding()
List {
ForEach(topEntities) { top in
TopRow(topEntity: top)
}
}
}.environment(\.locale, .init(identifier: language))
}
}
The above code seems to work ok, but has one cosmetic problem: the Menu displays the selected language a simple string "en" (or "de", or "ru"):
Being a Swift and SwiftUI newbie I do not understand, how to set the label to the nicer string, i.e. to the selected language and flag, like "πŸ‡ΊπŸ‡Έ EN". Please help
You can get the nice string from your labels dictionary. Here is the working version:
Menu(labels[language] ?? "Unknown") {
Button("πŸ‡ΊπŸ‡Έ EN", action: { language = "en" })
Button("πŸ‡©πŸ‡ͺ DE", action: { language = "de" })
Button("πŸ‡·πŸ‡Ί RU", action: { language = "ru" })
}.padding()
I just replaced language with labels[language] ?? "Unknown".

Sencha Touch2: Cannot close floating panel on Button click?

I am new to Sencha Touch2, i have problem while destroying the floating panel. I show floating Panel with details on top of ListView on list item click. I want the floating panel to be destroyed on 'Cancel' Button clicked.can anyone please help me. Thanks.
FloatingPanel.js:
Ext.define('CustomList.view.FloatingPanel', {
extend: 'Ext.Panel',
alias: 'widget.FloatingPanel',
xtype:'datepanel',
config: {
id:'floatingPanel',
modal:true,
centered: true,
hideOnMaskTap:true,
width:'500px',
height:'650px',
items:[
{
styleHtmlCls:'homepage',
tpl:'<h4>{name1}</h4><h3>{name2}</h3><h3>{name3}</h3><h3>{name4}'
},
{
xtype:'toolbar',
docked:'bottom',
items:[{
text:'OK',
ui:'confirm',
action:'ShowTurnOverReport',
listeners : {
tap : function() {
console.log('Ok');
}
}
},
{
text:'Cancel',
ui:'confirm',
action:'Cancel',
listeners : {
tap : function() {
console.log('Cancel');
var panelToDestroy = Ext.getCmp('floatingPanel');
panelToDestroy.destroy();
}
}
}]
}
]
}
});
Here is my List,
ShowList.js:
Ext.define('CustomList.view.ShowList',{
extend:'Ext.List',
xtype:'showlist',
requires: [
'Ext.dataview.List',
'Ext.data.Store',
'CustomList.controller.Main'
],
config:{
items:[
{
xtype:'list',
id: 'listitems',
onItemDisclosure: true,
store:'StoreList',
scrollable:'true',
itemTpl: [
'{firstname}'
],
itemTpl: '<font color="#990000"><h2>{lastname}</h2></font>{firstname}'
}
]
}
});
Here is my controller
Main.js
Ext.define('CustomList.controller.Main', {
extend: 'Ext.app.Controller',
requires:['CustomList.view.FloatingPanel'],
config: {
refs: {
listView: 'listitems'
},
control: {
'main test2 list': {
activate: 'onActivate',
itemtap: 'onItemTap'
}
}
},
onActivate: function() {
console.log('Main container is active');
},
onItemTap: function(view, index, target, record, event) {
console.log('Item was tapped on the Data View');
var name1 = record.get('name1');
console.log('Item was tapped on the Data View'+name1);
var floatingDatePanel = Ext.create('CustomList.view.FloatingPanel');
var data = record.getData();
floatingDatePanel.getAt(0).setData(data);
Ext.Viewport.add(floatingDatePanel);
}
});
One obvious problem is that:
Ext.getCmp('floatingPanel');
will be applied for case id: 'floatingPanel' whereas you use itemid:'floatingPanel'
To retrieve itemId, you can make use of Ext.ComponentQuery:
Ext.ComponentQuery.query('#floatingPanel')[0];

Sencha Touch 2: List and ListItem data fields

I wanted to know how to customize the ListItem content by combining different JSON data fields.
I have three JSON fields: {caption},{subCaption},{source}.
So far, I have been able to use dataMap and use custom classes to wrap additional text and styling around each. However, the only way I have been able to add content is to do so sequentially with the use of apply/update functions. As a result, my ListItems are simply {caption},{subCaption},{source} in their own lines.
Here's how I would like each ListItem to look like:
Combine {caption} and {subCaption} text and create a short story and add this as a panel to the ListItem
Render {source} in a small panel docked at the bottom right of the panel created in step 1.
How can I do the above? The distilled question would be: How can I access and combine the data from different JSON fields and render into ListItem?
My current code for ListItem is copied below for reference.
As always, any help is greatly appreciated! Thanks!
Mohammad
San Jose, CA
Ext.define('qxtapp.view.ResultsListItem', {
extend: 'Ext.dataview.component.ListItem',
requires: [
'qxtapp.view.ResultsListItemCaption'
],
xtype : 'resultslistitem',
alias : 'widget.resultslistitem',
config: {
caption: true,
subCaption: true,
source: true,
dataMap: {
getCaption: {
setHtml: 'caption'
},
getSubCaption: {
setHtml: 'subCaption'
},
getSource: {
setHtml: 'source'
}
},
layout: {
type: 'vbox'
}
},
applyCaption: function(config) {
return Ext.factory(config, qxtapp.view.ResultsListItemCaption, this.getCaption());
},
updateCaption: function(newCaption) {
if (newCaption) {
this.add(newCaption);
}
},
applySubCaption: function(config) {
return Ext.factory(config, Ext.Component, this.getSubCaption());
},
updateSubCaption: function(newSubCaption) {
if (newSubCaption) {
this.add(newSubCaption);
}
},
applySource: function(config) {
return Ext.factory(config, Ext.Component, this.getSource());
},
updateSource: function(newSource) {
if (newSource) {
this.add(newSource);
}
}
});
Ext.define('qxtapp.view.ResultsListItemCaption', {
extend: 'Ext.Component',
applyHtml: function(caption) {
// do some customization to caption and return it
return caption;
}
});
I'm not sure why you need to go through all that trouble, why not use an item template in a simple list?
Ext.define('qxtapp.view.ResultsList', {
extend: 'Ext.dataview.List',
alias: 'widget.resultslist',
config: {
...
itemTpl: new Ext.XTemplate(
"<div class='result-item'>",
"<p class='result-story'>",
"{[this.getStoryHtml(values.caption, values.subCaption)]}",
"</p>",
"<img src='{source}' alt='{caption}' />",
"</div>",
{
// This is a new function on the template created above and can be called
// from within the template html
getStoryHtml: function(caption, subCaption) {
// customize the text to your needs, then return the html to insert
}
}
),
...
}
});
Of course, you would then need to style these items using CSS, but that should be the easy part. ;)

EmberJS: How to create modal forms

Whats a good way or a pattern to creating modal forms in EmberJS. Something like this.
I will describe the way i manage modal views with a CSS approach:
Add CSS class names:
.modal {
-webkit-transition: -webkit-transform #modal-duration #ease-animation-style;
-webkit-transform: translate3d(0,0,0);
-webkit-backface-visibility: hidden;
}
.modal.from-left.is-hidden {
-webkit-transform: translate3d(-320px,0,0);
}
.modal.from-right.is-hidden {
-webkit-transform: translate3d(320px,0,0);
}
.modal.from-up.is-hidden {
-webkit-transform: translate3d(0,-1*#app-height,0);
}
.modal.from-down.is-hidden {
-webkit-transform: translate3d(0,#app-height,0);
}
Add custom events to your Application Namespace to receive the transitionEnd event in your view:
Yn.Application = Em.Application.extend( Em.Evented, {
customEvents: {
webkitTransitionEnd: 'transitionEnd',
......
}
});
Now create a mixin to be used in your view as:
Yn.Modal = Em.Mixin.create({
isHidden: true,
classNameBindings: ['isHidden'],
classNames: ['modal'],
transitionEnd: function(event) {
// transitionEnd triggers multiple times
// http://stackoverflow.com/questions/4062105/webkit-transitionend-event-grouping
if ( event.originalEvent.propertyName === '-webkit-transform' &&
$(event.target)[0] === this.$()[0] ) {
var eventName = this.get('isHidden') ? 'transitionHide' : 'transitionShow' ;
this.trigger(eventName);
}
}
});
You can now insert the view in the DOM via appendTo or any handlebars view template or whatever method you use, and manages your view with its isHidden property which can be bound for example to a controller UI property, you could also interact with the view with the view lifecycle hooks as didInsertElement or the new defined as transitionHide, transitionShow hooks.
You can use my modified Bootstrap.ModalPane
ex:
App.ContactView = Bootstrap.ModalPane.extend({
closeOnEscape: false,
showBackdrop: true,
showCloseButton: false,
heading: 'Contact',
primary: "Save changes",
secondary: "Cancel",
classNames: ["large-modal"],
bodyViewClass: Ember.View.extend({
templateName: 'contact-body'
}),
callback: function (opts, event) {
var controller = this.get('controller');
if (opts.primary) {
controller.save();
} else {
controller.cancel();
}
}
});
In you controller you can then do something like this:
editContact: function (contact) {
var contactController = this.controllerFor('contact');
contactController.set('content', contact);
var contactView = App.ContactView.create({
controller: contactController
});
contactView.append();
},
You can also define your own modalPaneTemplate with customizations. It's the principle of how the Boostrap.ModelPane works that matters, default it only supports 2 buttons at the bottom. If you want 5 buttons, or buttons in the header, start coding yourself and create a custom modalPaneTemplate.

List pushed in navigation view is not rendered

I am using sencha touch 2.
My App.js file (summed up)
Ext.application({
launch: function() {
// ...
var list = Ext.create('Ext.List', {
itemTpl : '<img src="{icon}"/>{title}<br/>{description}',
store: store,
listeners: {
select: function(view, record) {
var customView = Ext.create(record.get('view'));
navView.push(customView);
view.deselectAll();
}
}
});
//----------------------------------------------------------------------
var navView = Ext.create('Ext.NavigationView', {
navigationBar:{
items: [{
text:'refresh',
align: 'right'
}]
},
items: [list]
});
//----------------------------------------------------------------------
Ext.Viewport.add(navView);
}
});
When i am loading a view within my navigation view, everything is ok appart when it conains a list.
There is a view with a list in it.
The subpanel is rendered, but not the list view (the list view has been tested and is of course rendering in a different context)
Ext.define('ts.views.jobs', {
extend: 'Ext.Panel',
layout:'fit',
config:{
title:'Jobs'
},
initialize: function() {
this.callParent();
var jobsStore = Ext.create('Ext.data.Store', {
model: 'ts.model.job',
data: [{
key2: 'key1'
}, {
key2:'key2'
},
{
key2:'key3'
}
]
});
var jobsList = Ext.create('Ext.List', {
xtype: 'jobsList',
ui: 'round',
itemTpl : 'ok{key}',
store: jobsStore
});
var panel = Ext.create('Ext.Panel', {
html: 'Testing'
});
this.add([jobsList,panel]);
}
});
What am i doing wrong ?
* is it a navigationview bug ?
* am i not initializing properly in my subview ?
Thx for your help.
This was cross posted to the sencha touch forums: http://www.sencha.com/forum/showthread.php?184492-List-pushed-in-navigation-view-is-not-rendered and the answer accepted was:
layout config needs to be within the config object.