Agency-Watch Własne Aplikacje
Teraz z AgencyOS27: bezpłatna aktualizacja dla każdego, kto już posiada zegarek.

⌚ Zbuduj własną aplikację dla Agency-Watch
Zegarek jest otwarty. Właściciel serwera może dodać aplikację, która wygląda i działa jak wbudowana, używając tych samych elementów składowych, kolorów oraz tłumaczeń.
Wymóg: edycja Pro. Własne aplikacje działają tylko wtedy, gdy Agency-Phone jest uruchomiony na serwerze, a gracz go posiada. Bez wersji Pro są one rejestrowane, ale nigdy niedostarczane: interfejs nigdy się o nich nie dowie, nie pojawią się w App Store, a serwer odrzuci każde wysłane przez nie działanie. Jest to sprawdzane w trzech niezależnych miejscach i nie można tego wyłączyć.
| Plik | Wymagane | Co robi |
|---|---|---|
apps/<id>/app.lua | tak | Rejestruje aplikację: nazwa, ikona, kolor, kategoria. |
apps/<id>/app.js | tak | Ekran: co rysuje i jak reaguje. |
apps/<id>/app.css | nie | Twoje własne style. Ładowane tylko wtedy, gdy style = true. |
apps/<id>/server.lua | nie | Logika serwera, którą twoja aplikacja może wywołać. |
Folder ma dokładnie taką samą nazwę jak id aplikacji. W ten sposób zegarek znajduje app.js i app.css bez dwukrotnego wpisywania ścieżki, bo podwójnie zapisane ścieżki prędzej czy później zaczną się rozjeżdżać.
Wszystko pod apps/ to escrow_ignored: pozostaje czytelny i edytowalny na dysku, a aktualizacja watch nigdy go nie nadpisze.
1 Zarejestruj aplikację
apps/hello/app.lua
AgencyWatchApp({
id = 'hello', -- lowercase, digits and _, must match the folder
name = 'Hello',
icon = 'raster', -- one of the built-in icons, see below
color = '#5ac8fa', -- #rrggbb
category = 'tools', -- tools | games | driving | style | connected
style = true, -- also load app.css
texts = { en = 'Hello', de = 'Hallo' }, -- optional, name per language
})
Aplikacja z nieprawidłowym id, brakiem nazwy, nieznaną kategorią lub kolorem, który nie jest #rrggbb zostaje odrzucony, głośno i z podaniem powodu, w konsoli serwera. Połowiczna rejestracja nie istnieje: tego typu błąd pojawia się dopiero wtedy, gdy gracz w to kliknie.
Uruchom refresh i restart Agency-Watch po dodaniu plików. Przy starcie watch zgłasza zarejestrowane elementy.
2 Rysuj ekran
apps/hello/app.js
AgencyWatch.app('hello', {
render: function (w) { // required, returns HTML
var d = w.data();
return w.card('Hello, ' + w.esc(d.name)) +
w.section('Steps') +
w.row({ icon: 'schritte', static: true,
top: String(d.steps || 0) }) +
w.button('Roll a die', ' data-roll');
},
bind: function (w) { // optional, runs right after
w.click('[data-roll]', function () {
w.toServer('roll', { sides: 6 }).then(function (a) {
if (a.ok) w.notify('Hello', 'You rolled ' + a.data.value);
});
});
},
});
render uruchamia się za każdym razem, gdy ekran jest budowany, więc nie zachowuje stanu między wywołaniami. Wszystko, co musi przetrwać ponowne renderowanie, trafia do zmiennej poza obiektem aplikacji.
Obie funkcje działają w bezpiecznym środowisku. Jeśli twój kod wywoła wyjątek, aplikacja wyświetli linię błędu, a zegarek będzie działał dalej; właściwy błąd trafia do konsoli F8.
3 Skrzynka z narzędziami
w zawiera wszystko, czego potrzebuje aplikacja na zegarku, i nic ponadto. Interfejs, który potrafi wszystko, nigdy nie może zostać zmieniony, dlatego ten jest celowo niewielki.
| Zadzwoń | Co zyskujesz |
|---|---|
w.data() | Płaska migawka: time, hour, minute, date, weekday, name, job, health, armour, pulse, steps, distance, calories, speed, heading, weather, pro. |
w.row({icon, top, bottom, end, attrs, static}) | Wiersz listy w stylu zegarka. |
w.section(text) | Nagłówek sekcji. |
w.card(html) | Powierzchnia. |
w.button(text, attrs) | Przycisk. attrs to surowy ciąg atrybutów, np. ' data-roll'. |
w.toggle(on) | Przełącznik wł./wył. |
w.center(html) | Wyśrodkowany, dla pojedynczej dużej wartości. |
w.icon(name) | Jedna z wbudowanych ikon. |
w.esc(text) | Escapowanie tekstu. Użyj do wszystko który nie należy do ciebie. |
w.text(key, fallback) | Tłumaczenie z zegarka. |
w.click(selector, fn) | Podepnij listener. Tylko wewnątrz bind. |
w.notify(title, text, icon, colour) | Powiadomienie na zegarku. |
w.refresh() | Odrysuj ponownie, bez animacji wejścia. |
w.close() | Wróć, tak jak strzałka w nagłówku. |
w.toServer(action, data) | Zapytaj serwer. Zwraca promise. |
w.id, w.version | Twoje app id i wersja AgencyOS. |
Snapshot to kopia, a nie uchwyt. Zegarek zawiera także kontakty, wiadomości i dane kart; niczego z tego tam nie ma.
4 Strona serwera
apps/hello/server.lua
AgencyWatchAction('hello', 'roll', function(src, data)
local sides = tonumber(data and data.sides) or 6
if sides < 2 then sides = 2 end
if sides > 100 then sides = 100 end
return { value = math.random(1, math.floor(sides)) }
end)
w.toServer zawsze zwraca wynik, z { ok: true, data: … } lub { ok: false, reason: '…' }, nawet jeśli serwer nigdy nie odpowiedział. Twoja aplikacja nigdy nie zawiesi się w oczekiwaniu, a powód zawsze znajduje się na najwyższym poziomie, bez względu na to, która strona odmówiła.
reason | Znaczenie |
|---|---|
no_pro | Brak edycji Pro. Własne aplikacje bez niej nie istnieją. |
unknown | Brak zarejestrowanej aplikacji lub akcji. |
too_fast | Rate limit: maksymalnie dziesięć żądań na pięć sekund na gracza. |
error | Twój handler zgłosił błąd. Szczegóły znajdują się w konsoli serwera. |
timeout | Brak odpowiedzi w ciągu dwunastu sekund. |
data | Żądanie nie było tabelą. |
Cokolwiek trafi do data pochodzi od klienta i jest życzenie, nie fakt. Sprawdzaj każdą wartość przed jej użyciem. Wszystko, co ma znaczenie (pieniądze, przedmioty, rezultaty), należy do serwera i nigdzie indziej.
5 Stylowanie
Kolory zegarka są dostępne jako zmienne CSS i dopasowują się do wyboru użytkownika w Studio. Sztywno zakodowane kolory sprawiają, że aplikacja pozostaje niebieska na zielonym zegarku.
var(--text) var(--text-2) var(--leise)
var(--akzent) var(--gruen) var(--rot) var(--gelb)
var(--karte) var(--karte-hoch) var(--linie)
var(--grund)
Dodawaj prefiksy do własnych klas. Ekran jest współdzielony z każdą inną aplikacją, a klasa o nazwie .large znajdą przyjaciół.
6 Wbudowane ikony
Przekaż dowolne z nich do icon w app.lua lub do w.icon():
akku auto blitz brief einkauf farben flugzeug gewitter glocke haken helligkeit herz hoch hupe karte karte-pin kein-signal kino kompass kreuz krone lampe laufen lautlos links loeschen minus mobil mond nebel neuladen pause personen pin plus qr raster rechts regen regler runter sanduhr schild schloss schloss-auf schnee schritte signal sonne sp-fall sp-flug sp-ring sp-turm sprechen stoppuhr telefon telefon-aus tempo ton uhr verboten wiedergabe wlan wolke zahnrad
Nazwy ikon celowo pozostają bez zmian. Są to identyfikatory, a nie etykiety: gracz nigdy ich nie czyta, a zmiana nazwy id psuje każdą aplikację, która już z niego korzysta.
📦 Działający przykład jest dostarczany z zegarkiem
apps/example/ wewnątrz zasobu znajduje się kompletna, gotowa do uruchomienia aplikacja: komponenty, wywołanie serwera, powiadomienie i własny CSS. Skopiuj folder, zmień jego nazwę i masz już działający punkt wyjścia.
Skrócona wersja tej strony znajduje się w apps/README.md obok.