В этой статье Патрик Б., создатель Cypher poker, объясняет, как создавать и редактировать параметры начальной конфигурации. Примечания к объяснению были отредактированы мной. Учебник написан с точки зрения Патрика.

Что касается автоматического включения определенных функций при запуске, это можно сделать (это включено в EthereumStatusWidget). Что касается хранения данных между сессиями, это также можно сделать (это делается через GlobalSettings для гостиной и PokerGameSettings, когда игра активна).

Может быть немного сложно сохранить данные в настройках. Это большой XML-объект, и каждый виджет имеет ссылку на собственные настройки внутри этого объекта, а также на все дерево.

Вот как EthereumStatusWidget автоматически включает подключение при запуске в зависимости от настроек:

try {
var ethereumEnabled:Boolean = GlobalSettings.toBoolean(GlobalSettings.getSetting(“defaults”, “ethereum”).enabled);
} catch (err:*) {
ethereumEnabled = false;
}
this.toggle.addEventListener(Event.CHANGE, this.onToggleClick);
if (ethereumEnabled == true) {
this.enableautolaunch.isSelected = true;
this.enableautolaunch.invalidate();
}

Слушатель событий переключения — это всего лишь часть функции (не то, на чем стоит сосредоточиться). По сути, в try..catch мы пытаемся получить «включенный» узел в «эфириуме» в «по умолчанию», он находится в settings.xml:

<defaults>
<rtmfpgroup>CypherPoker.Lounge</rtmfpgroup>
<! — Leader status is assumed if no peer responses in leadertimeout seconds →
<leadertimeout>1</leadertimeout>
<! — If concurrency is disabled, the maxcryptoworkers value is ignored (only one pseudo-worker in the main thread will be used) →
<! — Additionally, if Worker functionality is unavailable in the runtime, this value will be forced to false. →
<concurrency>true</concurrency>
<! — Maximum number of concurrent crypto workers. Practical maximum is usually 3 but this should be measured per device. →
<maxcryptoworkers>3</maxcryptoworkers>
<! — Maximum period, in milliseconds, to retry an operation with a currently busy cryptoworker. →
<workerbusyretry>999</workerbusyretry>
<! — Maximum period, in milliseconds, to delay between some consecutive operations to accomodate multiple instances on the same device →
<multiinstancedelay>150</multiinstancedelay>
<! — Default Crypto Byte Length →
<cryptobytelength>30</cryptobytelength>
<ethereum>
<enabled>false</enabled>

Обратите внимание на последний узел… <enabled>false</enabled>

Это то, к чему обращаются в «try..catch»

Часть try пытается получить данные из settings.xml, но если он не существует (или что-то еще пойдет не так), в части catch устанавливается значение по умолчанию.

Тогда в if (ethereumEnabled == true) { я просто запускаю соединение (или нет), исходя из настройки.

Таким образом, вы, вероятно, захотите добавить свою собственную настройку в какой-либо соответствующий раздел файла settings.xml, а затем получить к ней доступ в функции «инициализировать», чтобы она выполняла свою работу при запуске.

Большинство виджетов работают примерно одинаково. Многим из них не нужна информация о запуске, но некоторым она нужна.

Основная настройка извлекается следующим образом:

GlobalSettings.getSetting(“defaults”, “ethereum”).enabled

Это означает, что в «GlobalSettings» (данные settings.xml) найдите узел с именем «defaults», внутри него найдите «ethereum» и внутри него «включите».

Это немного неуклюже, потому что, когда я впервые написал это, я не думал, что мне нужно углубиться более чем на 2 уровня в XML. Часть «.enabled» — это третий уровень, и оттуда можно пойти еще глубже, но я стараюсь, чтобы он был довольно поверхностным.

Если вы настроите свой собственный узел, скажем, что-то вроде этого:

<settings version=”2.1a”>
<netcliques>
<definition id=”RTMFP_INET” type=”direct” class=”p2p3.netcliques.RTMFP”>
<name>RTMFP on Internet</name>
<description>Assisted peer-to-peer connectivity using Rendezvous and RTMFP over the internet.</description>
<init>

<defaults>
<ethtransferwidget>
<enabled>true</enabled>

Вы можете получить к нему доступ, используя: GlobalSettings.getSetting(“defaults”, “ethtransferwidget”).enabled

Вызов `getSetting` возвращает объект String, поэтому вы можете сохранить его как:

var startupenabled:String = GlobalSettings.getSetting(“defaults”, “ethtransferwidget”).enabled.toString();

Затем сравните содержимое узла следующим образом:

if (startupenabled == “true”) {
//do stuff
} else {
//do nothing
}

В моей версии я использую другую функцию в GlobalSettings, чтобы преобразовать ее в логическое значение (true/false):

var ethereumEnabled:Boolean = GlobalSettings.toBoolean(GlobalSettings.getSetting(“defaults”, “ethereum”).enabled);

Функция toBoolean может обрабатывать всевозможные варианты, такие как «истина», «ложь», «включено», «отключено», «1», «0» и так далее. Но если вы можете быть уверены, что точно знаете, какими будут данные, вам не нужно этого делать.

Не забудьте включить import org.cg.GlobalSettings, чтобы использовать его!

Кроме того, в верхней части класса Lounge включите повторную загрузку данных конфигурации из файла:

public static const resetConfig:Boolean = true; //Load default global settings data at startup?

Эти данные сохраняются в нечто, называемое локальным общим объектом, которое является общим для всех сред выполнения, поддерживаемых ActionScript. Тот же механизм можно использовать для хранения данных конфигурации для настольной версии, веб-версии, мобильной версии и т. д. Исходные (по умолчанию) данные конфигурации … settings.xml … остаются на диске.

Вот еще немного о классе SharedObject, если вам интересно: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/SharedObject.html

Одна вещь, которую вы можете попробовать сделать, это установить другую строку в узле <enabled>. Не преобразовывайте его в логическое значение, просто прочитайте его как строку и отобразите в выводе отладки, чтобы увидеть, действительно ли вы к нему обращаетесь. Для этого есть класс для отладки: org.cg.DebugView Импортируйте его и вызовите следующим образом:

DebugView.addText(“Some text to add”);

Вы можете добавить туда все, что хотите просмотреть, а не только строку, как я показываю. Вывод будет отображаться в окне «вывода» FlashDevelop, и вы также можете вызвать внутреннее представление отладки, используя ALT-D (или это CTRL-D? один из двух :slightly_smiling_face: )

Итак, вы можете сделать что-то вроде этого:

DebugView.addText (“Widget enabled setting: “+GlobalSettings.getSetting(“defaults”, “ethtransferwidget”).enabled);

Поскольку это, предположительно, будет в функции «инициализации», вы должны увидеть этот текст в выводе после запуска приложения. Если есть проблема, например, неправильно сформирован XML или этот узел недоступен, вы получите ошибку времени выполнения.

С сохранением данных немного сложнее. Я обычно разбиваю его на части, чтобы было легче читать. Здесь я сохраняю адрес клиента Ethereum и настройки порта из EthereumStatusWidget в глобальные настройки:

var ethereumSettings:XML = GlobalSettings.getSetting(“defaults”, “ethereum”);
var addressNode:XML = ethereumSettings.child(“clientaddress”)[0];
var portNode:XML = ethereumSettings.child(“clientport”)[0];
addressNode.replace(“*”, new XML(“<![CDATA[“ + this.clientAddressInput.text + “]]>”));
portNode.replace(“*”, new XML(this.clientPortInput.text));
GlobalSettings.saveSettings();

Функция getSetting возвращает объект XML. Это не сработает:

var startupenabled:String = GlobalSettings.getSetting(“defaults”, “ethtransferwidget”).enabled;

var startupenabled:XML = GlobalSettings.getSetting(“defaults”, “ethtransferwidget”).enabled;

Или, если мы хотим использовать строку, то:

var startupenabled:String = GlobalSettings.getSetting(“defaults”, “ethtransferwidget”).enabled.toString();

Вы получите ошибку компилятора, если попробуете эту первую строку.

Следующие строки, вероятно, нуждаются в некотором объяснении. Когда я получаю ethereumSettings в первой строке, я использую этот объект для получения узла <address> следующим образом:

var addressNode:XML = ethereumSettings.child(“clientaddress”)[0];

Функция .child возвращает массив всех дочерних узлов в пределах etherumSettings , которые соответствуют имени «clientaddress». Должен быть только один, поэтому я просто использую первый найденный экземпляр как стандартный элемент массива: [0]

Когда у нас есть ссылка на узел, с которым мы хотим работать, мы заменяем все его содержимое (дочерние элементы), делая что-то вроде этого:

addressNode.replace(“*”, new XML(“<![CDATA[“ + this.clientAddressInput.text + “]]>”));

Это означает .replace все ("*") содержимое addressNode с новым XML-объектом: XML(“<![CDATA[“ + this.clientAddressInput.text + “]]>”)

Это выглядит немного запутанным, так как я использую узел CDATA (https://en.wikipedia.org/wiki/CDATA)

Это немного более очевидно, когда я обновляю clientport node:

portNode.replace(“*”, new XML(this.clientPortInput.text))

Объект new XML создается с любым текстом, найденным в поле clientPortInput text. Это то, что я добавил недавно, поэтому вы можете не увидеть его в своем пользовательском интерфейсе.

В пользовательском узле, который мы создали для вашего виджета, вы должны сделать что-то вроде этого:

var startupenabled:XML = GlobalSettings.getSetting(“defaults”, “ethtransferwidget”).enabled;
startupenabled.replace(“*”, new XML(“nope”));

Здесь я жестко запрограммировал «нет» в качестве строки для установки. Обновленный XML будет выглядеть так:

<defaults>
<ethtransferwidget>
<enabled>nope</enabled>

Важно отметить, что все XML-дерево связано, так что все, что мы действительно сделали здесь, это изолировали, какой узел мы хотели обновить, и обновили его. Мы не создали копию данных настроек или чего-то еще (многие путаются). Когда я говорю, что мы получаем «ссылку» на что-то, мы просто указываем на объект и работаем с ним, а не создаем копию. На самом деле можно создать копию, но это нужно сделать явно.

В последней строке обновленные данные XML сохраняются в локальный общий объект:

GlobalSettings.saveSettings();

Наверное, самая легкая часть. Когда приложение запускается в следующий раз, общий объект считывается, если только мы прямо не укажем, что хотим загрузить файл settings.xml в классе Lounge. Если данные общего объекта не существуют (что может произойти, если мы никогда раньше не запускали приложение), данные settings.xml считываются автоматически и сохраняются в общем объекте.

Когда мы вызываем saveSettings , мы буквально сохраняем весь объект конфигурации; все виджеты, макеты и т. д. Если вы хотите, вы можете поиграть с конфигурациями других виджетов и сохранить их, чтобы их данные изменились при следующем запуске. Обычно это не очень хорошая идея, если виджет не предназначен специально для обновления других виджетов… но ничто не мешает вам это сделать!

Вы можете изменить порядок виджетов, изменить состав их компонентов и способ их отображения, изменить доступные параметры подключения... буквально все, что отображается в данных settings.xml, можно изменить с помощью те же процедуры, описанные выше.

Последнее замечание: я работаю над классом средства обновления настроек, который будет принимать новые данные настроек и добавлять/обновлять их в глобальных настройках (в общем объекте). Я все еще дорабатываю формат файла «update.xml»… даже не уверен, что назову его так… но в одном я уверен: нам нужно будет отслеживать узлы, которым нужно быть добавлены или изменены между версиями. Например, если мы хотим добавить EtherTransferWidget в следующую версию, это, очевидно, нужно будет указать в данных настроек, чтобы программе обновления нужно было знать, что добавлять. Поэтому следите за всем, что вы добавили или обновили в XML-данных настроек.

Ваш виджет потенциально мог бы позаботиться о создании всех своих собственных настроек, но его по крайней мере необходимо добавить где-нибудь в узел <views>, чтобы визуализатор виджета действительно мог его создать. Если его нет в этом узле, то он не будет создан, даже если он был добавлен в скомпилированный код.