Reading an array from another Class - arrays

I have a Class on a Theme.swift called Themes file which basically defines some types of Strings, and set different colours and font types.
On another file, called Contents.swift I have another class called Contents, and some arrays, like this:
class Contents: Themes {
let navContent = [
LabelContent(text: "NAV IDENT", theme: .menuOption),
LabelContent(text: "WPT LIST", theme: .menuOption)
]
}
The question is:
How can I use this navContent array in AppDelegate? It's not global yet I think.

If you don't want to create an instance of the class Contents and then get its properties, then make those properties static (or Type Properties):
class Contents: Themes {
static let navContent = [
LabelContent(text: "NAV IDENT", theme: .menuOption),
LabelContent(text: "WPT LIST", theme: .menuOption)
]
}
And you could access them like so:
print(Contents.navContent[0])
Here is a brief description of Type Properties from the documentation:
You can define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.

if it's a member variable of the Contents class as you have it there, you need to create an instance of Contents, then access it from the instance
let instance = Contents()
instance.navContent // access it this way
if you dont want to create an instance everytime you need to access it, then you can make it into static class variable
class Contents: Themes {
static let navContent = [
LabelContent(text: "NAV IDENT", theme: .menuOption),
LabelContent(text: "WPT LIST", theme: .menuOption)
]
}
Contents.navContent // access it this way
if you need polymorphism on that variable, you can use the 'class' keyword on the variable and you can override it on the child class (but it needs to be a computed variable). you access it the same way as static class variable
class Contents: Themes {
class var navContent: [LabelContent] {
return [LabelContent(text: "NAV IDENT", theme: .menuOption)]
}
}
class OtherContents: Contents {
override class var navContent: [LabelContent] {
return [LabelContent(text: "WPT LIST", theme: .menuOption)]
}
}
Contents.navContent // access "NAV IDENT"
OtherContents.navContent // access "WPT LIST"

Related

Swift initializing image variables differently does not work

I have a JSON file from which I two icon names: normal and active.
I use them to get the system icons, which I'd like to put inside an image array.
When I load them separately it works just fine:
struct loadData: Hashable, Codable {
//load some data...
private var normal_name: String
private var active_name: String
var normal_icon: Image {
Image(systemName: normal_name)
}
var active_icon: Image {
Image(systemName: normal_name)
}
}
When I try to put the acquired images inside an array, it throws an error:
var icon: [Image] = [
normal_icon,
active_icon
]
Even if I try to load them directly, it still throws the same error:
var icon: [Image] = [
Image(systemName: normal_name),
Image(systemName: normal_name)
]
The error I get is this:
Cannot use instance member 'normal_icon' within property initializer; property initializers run before 'self' is available
I know I can use a computed property to fix this issue, my question is:
Why am I allowed to initialize the string (normal_name) and then initialize the image (normal_icon) without getting an error, but when I do it inside the array it doesn't work?
You don't show us the context where the code:
var icon: [Image] = [
normal_icon,
active_icon
]
lives, but are you doing this?:
struct loadData: Hashable, Codable {
//load some data...
private var normal_name: String
private var active_name: String
var icon: [Image] = [
normal_icon,
active_icon
]
}
If so, then you have to realize that normal_icon in the array declaration is really a reference to self.normal_icon so it is referencing self while trying to set up the field icon. But the fields of the object are initialized before self is available so you
Cannot use instance member 'normal_icon' within property initializer; property initializers run before 'self' is available

How do you generate a single file containing the parent class and all child classes?

I've currently got a tst that generates the parent class, but the child classes need to be listed separately in the file as well so that I end up with 1 file that contains all necessary files for the front end.
key parts of the tst look like this at the moment:
$Imports
$Classes([TsType])[
export interface $Name $Extends {
$Properties(o=>o.Attributes.Any(a=>a.Name=="TsIgnore")==false)[
$name$IfOptional: $TypeNamespace$Type;]
}]
$Classes(*Generic)[
class $Name$TypeParameters {
$Properties[
public $name: $Type;]
}]
$Enums([TsType])[
export enum $Name{
$Values[
$name,
]
}
]
In the $Classes you can access the $NestedClasses. See here: http://frhagn.github.io/Typewriter/pages/documentation.html
$Classes(*Generic)[
class $Name$TypeParameters {
$Properties[
public $name: $Type;]
$NestedClasses(*Generic)[
class $Name$TypeParameters {
$Properties[
public $name: $Type;]
}]
}]

Using the MediaPicker property editor in custom property (Umbraco)

I want to create a custom property editor, that makes use of the media picker. Right now my controller looks like this:
angular.module("umbraco").controller("My.MediaCropperController",
function($scope, dialogService) {
$scope.mediaPicker = {
view: 'mediapicker',
value: null, // or your value
config: { disableFolderSelect: true, onlyImages: true }
};
});
And my view looks like this:
<umb-editor ng-controller="My.MediaCropperController" model="mediaPicker" ng-if="mediaPicker">
</umb-editor>
As I understand it, I need to create config object for built-in editors, then use in the template to show the editor. However when i bring my property editor into my backoffice, nothing is being shown. What am I doing wrong here?
This is my package manifest file:
{
//you can define multiple editors
propertyEditors: [
{
/*this must be a unique alias*/
alias: "My.MediaCropper",
/*the name*/
name: "My Media Cropper",
/*the html file we will load for the editor*/
editor: {
view: "~/App_Plugins/MediaCropper/mediacropper.html"
}
}
]
,
//array of files we want to inject into the application on app_start
javascript: [
'~/App_Plugins/MediaCropper/mediacropper.controller.js'
]
}
dialogService.mediaPicker rather than $scope.mediapicker ?
May be what is causing your error, just from comparing my script to yours.

How to make custom theme using Shoutem's StyleProvider that properly uses underlying INCLUDE

I really love the shoutem theme library, but I'm finding it difficult to hook into the recursive INCLUDE that makes the underlying code work beautifully (See code+documentation here: https://github.com/shoutem/theme/blob/develop/src/Theme.js). For instance, if we have:
render() {
return (
<StyleProvider style={theme}>
<View />
</StyleProvider>
);
}
const theme = _.merge(getTheme(), {
'shoutem.ui.Text': {
color: 'green',
},
});
This simple text color change will work, but only for shoutem Text components. However, Heading, Title, Subtitle, etc. all of which pull from Text attributes in the shoutem library because of INCLUDE. The use of a simple _.merge(...) only overwrites the component itself, but not anything that it might subsequently affects. It sounds like I need to overwrite attributes higher up in the tree (e.g., Text), and then regenerate the theme so it affects all "children" that it's included in (e.g., Heading and Title). Using the publicly exposed API, is this possible to do somehow at the moment? Or are there any forks or utilities you're aware of that accomplish this with your library.
There is a text property in the root of the default shoutem ui theme that is included into all text elements (https://github.com/shoutem/ui/blob/develop/theme.js#L292). You should be able to accomplish your use case by simply overriding values from that property:
const theme = _.merge(getTheme(), {
text: {
color: 'green',
},
});
In case you want to create a more complex theme, you can use INCLUDE in your code as well. INCLUDE works by merging all values from top level theme properties it targets. You can use it to include properties from the base theme, and you can also include your own custom properties:
import { INCLUDE } from '#shoutem/theme';
const theme = _.merge(getTheme(), {
// Define a top level property to use in includes
largeText: {
fontSize: 20,
},
'shoutem.ui.Text': {
// Include a text property from the base theme
// and a largeText property defined above
[INCLUDE]: ['text', 'largeText'],
// Override the text color after all includes
// have been resolved
color: 'green',
},
});
Sometimes specific components define styles after INCLUDEs have been resolved, those styles have a higher priority, and will always override the style from INCLUDEs. To change those styles, you can use a createSharedStyle helper:
import { createSharedStyle } from '#shoutem/theme';
const textComponents = [
'shoutem.ui.Heading',
'shoutem.ui.Title',
'shoutem.ui.Subtitle',
'shoutem.ui.Text',
'shoutem.ui.Caption',
];
const theme = _.merge(getTheme(), {
...createSharedStyle(textComponents, {
color: 'green',
},
});
Finally, some more basic customizations can be done through theme variables, you can pass custom variables when calling getTheme(https://github.com/shoutem/ui/blob/develop/theme.js#L55-L144).

Path notification for changes to an object within an array?

We have a large model object that is owned and managed outside of polymer. We want to expose this model to polymer elements through a proxy element that exposes computed parts of it.
For example, the model may have:
{
blocks: {
...
properties: [
{ ... }, // prop0
{ ... }, // prop1
]
},
}
We are using recursive object observers and array observers to monitor changes to the model and notify polymer appropriately (either using .notifyPath(path, ...) for object changes and ._notifySplice(...) for array changes). However, there doesn't seem to be a good way for us to notify of changes to an object within an array, e.g. prop0 changed in the example above.
Is there? What should the path be?
Here's an example using binding to show an updated Polymer property nested inside an object and array:
code:
<div>
<h1>[[blocks.properties[0]]]</h1>
<p>this updated property should read: Apple</p>
</div>
script:
Polymer({
is: "my-page",
properties: {
blocks: {
type: Object,
value: { properties : ["acorn","banana","carrot"] },
notify: true
},
},
attached: function() {
console.log("update");
this.set('blocks.properties[0]', "Apple");
},
If you need to do array functions you should also use this.push(path, value) or this.splice(path, value) to notify changes.

Resources