Skip to content
View in the app

A better way to browse. Learn more.

FGX Native

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Yaroslav Brovin

Administrators
  • Joined

  • Last visited

  1. Hello @Stefan Diestelmann , Could you attach you svg file? We coould check our parser and possibly add missed features in our SVG implementation. We don't support full SVG standard, because it's too much big and support alot of thing, what is too much for mobile platforms (from performance side). We aim on supporting SVG 1.1 (https://www.w3.org/TR/SVG11/). Clipping hasn't not finished yet. When you create SVG, you should finally save it as simplified SVG format (For example. Inkscape provides different export options for it and allows to save it with simplified svg instruction with limited count of command). Thank you.
  2. Download: RAD Studio 12.*-13.0 setup_1.19.6.0_release.eng.zip Release date: 03 June 2026 New ✨TfgWebBrowserTwo new events have been added: OnPermissonRequest and OnConsoleMessage. Added a new demo project: "Components" -> "TfgWebBrowser" -> "Request Permissions" PermissionsThe OnPermissonRequest event allows you to control web browser access to the camera, microphone, and private media data. The event is triggered at the moment when the downloaded content in the browser wants to gain private access to the camera, microphone, or other resources. A set of requested AResources resources is passed to the event input: TfgPermissionResource = (AudioCapture, VideoCapture, ProtectedMedia); TfgPermissionResources = set of TfgPermissionResource; TfgPermissionRequestEvent = procedure(Sender: TObject; const AUrl: string; const AResources: TfgPermissionResources; const AHandler: IFGXPermissionRequestHandler) of object;The AHandler is used to confirm or reject such access. In this event, you need to make such a request to the system, and upon receiving confirmation from the user, inform the browser that access is allowed by calling AHandler.Grant(Resources). If no access is granted - AHandler.Deny. Please note that the system permissions are requested via TfgPermissionService.RequestPermissionsAsync are issued for your entire application. This means that any component and code within your application automatically gets access. However, the web browser allows you to load any content dynamically. And so that the content of the web browser cannot monitor the user (subject to previously granted access), it automatically requests such access permission from the developer through a new event. If the developer does not grant such access or does not write a handler, such an access request is automatically considered rejected. Also, this event does NOT request access to the camera or microphone from the system, but only allows you to block such access. If you approve this access at this event, but do not get permission from the system, the browser will not be able to use the camera and microphone. This event is only relevant for the Android platform. By default, iOS automatically requests such access from the user automatically. ConsoleThe OnConsoleMessage event allows you to intercept a message output by Javascript to the web browser console. It only works on Android. Improvements 🙌TfgCollectionViewThis release has changed the approach to dynamically calculating the size of TfgCollectionView elements. Despite the fact that the list allowed for changing the heights (for a vertically oriented list) of elements, the solution we proposed was not fully consistent with how the list works in iOS. As you know, the display of elements in the TfgCollectionView does not depend on their number. Because only visible elements are always displayed. Despite the fact that the working principle of the list is similar in Android and iOS, there is still a difference: In the Android, you will never know the total size of the list items (aka ContentSize) and the exact offset of the contents of the ContentOffset. To find out the exact offset of the list and the size of the content, it would have to load all the elements first in order to find out the actual height of each element. But for the speed of work in Android, this is not done. Therefore, the offset is calculated based on the average height of the elements in the visible window (the sliding window algorithm is used). This means that in Android, you can change the size of an element at any time with impunity, because this does not affect the calculation of the offset and the size of the content in the Android component's paradigm. In the iOS, the situation is completely the opposite, the list first asks for the sizes of all the elements and only then outputs them. Therefore, any change in the size of the elements after the list has requested all the sizes and performed all the heavy calculations leads to a very difficult updating of the internal state of the list with further problems in speed. Starting with iOS 26, any such attempt to resize ends up crashing the app, because the native implementation of the list does not take this into account. Therefore, we had to rethink the approach to the dynamic calculation of the heights of the elements.: If you plan to change the height of the elements dynamically, now you need to explicitly indicate this to the list by setting the value of the new TfgCollectionViewStyle.VariableSize = True property. By default, the value is set to `False`. If this is not done, the set size of the elements in the OnBindItem will be ignored and the style size taken from the designer will be used. As before, the calculation of the height of the elements must be performed in TfgCollectionView.OnBindItem. The specified height is cached in the list and used to speed up the list. When changing the size of the list, as well as when calling `ReloadItems` and other similar methods, the cache is automatically reset and you will be prompted to recalculate the sizes of the elements in TfgCollectionView.OnBindItem. If for some reason you want to recalculate the size of an element, then you need to inform the list about this by calling the methods ReloadItems, ReloadItem. If this is not done, any attempt to set a new size that differs from the original one will be ignored by the list. Let's take an example. We have a simple list with the elements displayed by the label using a single component of the style TfgLabel (text). Then an auxiliary method that calculates the height of the label at a fixed width may look like this: procedure TFormMain.AdjustHeight(const AItem: TfgItemWrapper); begin var LLabel := AItem.GetControlByLookupName<TfgLabel>('text'); if LLabel = nil then Exit; var Item := AItem.Item; // Calculating the available width of the label for text output, taking into account the external and internal margins var TotalHItemPadding := Item.Padding.LeftRtl + Item.Padding.RightRtl; var TotalHLabelMargins := LLabel.Margins.LeftRtl + LLabel.Margins.RightRtl; var TotalVLabelMargins := LLabel.Margins.Top + LLabel.Margins.Bottom; var ContentWidth := Item.Width - TotalHItemPadding - TotalHLabelMargins; // Calculating the size of the label for displaying the text, taking into account the fixed width. var Sz := LLabel.MeasureSize(TfgMeasuringSpecification.Fixed, ContentWidth, TfgMeasuringSpecification.Unspecified, 0); Item.Height := Sz.Height + TotalVLabelMargins; end;Then binding the elements to the data and setting the size will look like this: procedure TFormMain.cvListBindItem(Sender: TObject; const AIndex: Integer; const AStyle: string; const AItem: TfgItemWrapper); var ItemText: string; begin ItemText := FItems[AIndex]; var LLabel := AItem.GetControlByLookupName<TfgLabel>('text'); if LLabel <> nil then LLabel.Text := ItemText; AdjustHeight(AItem); end;Important. Don't forget to set TfgCollectionViewStyle.VariableSize = True for style. TfgNavigationBarThe appearance settings of ActionButtons were extended. The new property Icon was introduced for TfgNavigationBarButton. It allows to adjust default icon appearance on button level. It provides: RenderMode - It is responsible for whether the icon needs to be repainted in a given shade or whether the icon should be displayed as it is. TintColor/TintColorName - the color of the icon shade. Allows you to redefine the icon shade set via the TfgNavigationBar.ButtonsOptions.IconTintColor/IconTintColorName property by default. TfgLabelThe TfgLabel HTML parser has been unified across all platforms. Text display in the designer has been added for the TfgLabel.TextType = TfgTextType.HTML mode. A multi-line text editor for TfgLabel.Text has been added when editing in the object inspector. Bug Fixes 🐛Fixed data generation in info.plist to support working with UIScene. FGX-439 MoveCameraToVisibleRegion still doesn't work. FGX-474 Assets Designer. The renaming empty folder removed this folder. FGX-501 TfgCollectionView was crashed on the iOS 26+ (iOS). The exception in openning form designer in the IDE 13.1 was fixed. It requires select designer for version 13.1 in installator. In recent versions of iOS, using TfgCollectionView and TfgLabel together in TfgTextType.HTML mode could lead to crashes.
  3. Скачать: RAD Studio 12.* - 13.0 setup_1.19.6.0_release.rus.zip Дата релиза: 3 июня 2026 Новое ✨TfgWebBrowserДобавлены два новых события: OnPermissonRequest и OnConsoleMessage. Добавлен новый демонстрационный проект: "Компоненты" -> "TfgWebBrowser" -> "Запрос разрешений" Работа с разрешениямиСобытие OnPermissonRequest позволяет управлять доступом веб-браузера к камере, микрофону и приватным медиа данным. Событие вызывается в тот момент, когда загружаемый контент в браузере хочет получить приватный доступ к камере, микрофону или другим ресурсам. На вход события передается набор запрашиваемых ресурсов AResources: TfgPermissionResource = (AudioCapture, VideoCapture, ProtectedMedia); TfgPermissionResources = set of TfgPermissionResource; TfgPermissionRequestEvent = procedure(Sender: TObject; const AUrl: string; const AResources: TfgPermissionResources; const AHandler: IFGXPermissionRequestHandler) of object;AHandler используется для подтверждения или отклонения такого доступа. Вам необходимо в этом событие сделать такой запрос системе, и по получении подтверждения от пользователя сообщить браузеру, что доступ разрешен посредством вызова AHandler.Grant(Resources). Если же никакой доступ не выдан - AHandler.Deny. Обратите внимание, что системные разрешения запрашиваемые через TfgPermissionService.RequestPermissionsAsync выдаются на все ваше приложение. А это значит, что любой компонент и код в рамках вашего приложения автоматически получает доступ. Однако, веб-браузер позволяет подгружать любой контент динамически. И чтобы контент веб браузера не мог следить за пользователем (при условии ранее выданного доступа), он автоматически запрашивает такое разрешение доступа у разработчика через новое событие. Если же разработчик не выдает такой доступ или же не пишет обработчик, такой запрос доступа автоматически считается отклоненным. Также, это событие НЕ запрашивает доступ к камере или микрофону у системы, а лишь позволяет вам заблокировать такой доступ. Если вы одобрите этот доступ в этом событие, но не получите разрешение у системы, то браузер не сможет использовать камеру и микрофон. Данное событие актуально только для платформы Андроид. По сколько iOS автоматически запрашивает такой доступ у пользователя автоматически. КонсольСобытие OnConsoleMessage позволяет перехватить сообщение, выводимое Javascript в консоль веб-браузера. Работает только на Андроид. Улучшения 🙌TfgCollectionViewВ этом релизе изменен подход к динамическому расчету размеров элементов TfgCollectionView. Несмотря на то, что список допускал изменение высот (для вертикально ориентированного списка) элементов, предложенное нами решение не являлось до конца согласованным с тем, как работает список в iOS. Как вы знаете, отображение элементов в TfgCollectionView не зависит от их количества. Потому что всегда отображаются только видимые элементы. Несмотря на то, что принцип работы списка схож в Android и iOS, разница все же есть: В Андроиде вы никогда не узнаете суммарный размер элементов списка (он же ContentSize) и точное смещение содержимого ContentOffset. Чтобы узнать точное смещение списка и размер содержимого, ему пришлось бы вначале загрузить все элементы, чтобы узнать у каждого элемента его реальную высоту. Но для скорости работы в Андроиде это не делается. Поэтому расчет смещения выполняется по среднему значению высот элементов в видимом окне (используется алгоритм скользящего окна). И значит в Андроиде можно безнаказанно менять размер элемента в любой момент времени, потому что это не влияет на расчет смещения и размер содержимого в парадигме работы компонента под Android. В iOS же ситуация полностью противоположная, список первым делом запрашивает размеры у всех элементов и только потом их выводит. Поэтому любое изменение размера элементов уже после того, как список запросил все размеры и провел все тяжелые вычисления, приводит к очень сложной актуализации внутреннего состояния списка с дальнейшими проблемами в скорости работы. Начиная с iOS 26 любая такая попытка изменения размера заканчивается падением приложения, потому что нативная реализация списка это не учитывает. Поэтому нам пришлось переосмыслить подход к динамическому расчету высот элементов: Если вы планируете менять высоту элементов динамически, то теперь необходимо явно об этом указать списку, установив значение нового свойства TfgCollectionViewStyle.VariableSize = True. По умолчанию, значение равно False. Если этого не сделать, то установленный размер элементов в OnBindItem будет проигнорирован и будет использован размер стиля, взятый из дизайнера. Как и ранее, расчет высоты элементов необходимо осуществлять в TfgCollectionView.OnBindItem. Указанная высота кешируется в списке и используется для ускорения работы списка. При изменении размера списка, а также при вызове ReloadItems и других аналогичных методов, кеш автоматически сбрасывается и вам будет предложено повторно пересчитать размеры элементов в TfgCollectionView.OnBindItem. Если по каким-то причинам, вы хотите пересчитать размер элемента, то вам необходимо сообщить списку об этом по средством вызова методов ReloadItems, ReloadItem. Если этого не сделать, то любая попытка задать новый размер, который будет отличаться от первоначального, будет проигнорирована списком. Рассмотрим пример. У нас есть простой список с элементами, отображаемыми надпись при помощи единственного компонента стиля TfgLabel (text). Тогда вспомогательный метод, выполняющий расчет высоты метки при фиксированной ширине может выглядеть так: procedure TFormMain.AdjustHeight(const AItem: TfgItemWrapper); begin var LLabel := AItem.GetControlByLookupName<TfgLabel>('text'); if LLabel = nil then Exit; var Item := AItem.Item; // Выполняем расчет доступной ширины метки для вывода текста с учетом внешних и внутренних отступов var TotalHItemPadding := Item.Padding.LeftRtl + Item.Padding.RightRtl; var TotalHLabelMargins := LLabel.Margins.LeftRtl + LLabel.Margins.RightRtl; var TotalVLabelMargins := LLabel.Margins.Top + LLabel.Margins.Bottom; var ContentWidth := Item.Width - TotalHItemPadding - TotalHLabelMargins; // Выполняем расчет размера метки для отображения текста с учетом фиксированной ширины. var Sz := LLabel.MeasureSize(TfgMeasuringSpecification.Fixed, ContentWidth, TfgMeasuringSpecification.Unspecified, 0); Item.Height := Sz.Height + TotalVLabelMargins; end;Тогда связывание элементов с данными и задание размера будет выглядеть так: procedure TFormMain.cvListBindItem(Sender: TObject; const AIndex: Integer; const AStyle: string; const AItem: TfgItemWrapper); var ItemText: string; begin ItemText := FItems[AIndex]; var LLabel := AItem.GetControlByLookupName<TfgLabel>('text'); if LLabel <> nil then LLabel.Text := ItemText; AdjustHeight(AItem); end;Так же не забываем, что для стиля нужно указать TfgCollectionViewStyle.VariableSize = True. TfgNavigationBarРасширены настройки отображения иконки кнопок ActionButtons. Для кнопки TfgNavigationBarButton введено новой свойство Icon, отвечающее за настройку отображения иконки на кнопке. Теперь доступны следующие настройки: RenderMode - отвечает за нужно ли перекрашивать иконку в заданный оттенок или выводить иконку, как она есть. TintColor/TintColorName - цвет оттенка иконки. Позволяет переопределить оттенок иконки, заданный через свойство TfgNavigationBar.ButtonsOptions.IconTintColor/IconTintColorName по умолчанию. TfgLabelУнифицирован парсер HTML TfgLabel для всех платформ. Для режима TfgLabel.TextType = TfgTextType.HTML добавлено отображение текста дизайнере. Добавлен многострочный редактор текста TfgLabel.Text при редактировании в инспекторе объектов. Исправление ошибок 🐛Исправление генерации данных в info.plist для поддержки работы с UIScene. FGX-439 MoveCameraToVisibleRegion всё еще не работает. FGX-474 Assets Designer. При попытке переименовать пустую папку она пропадает. FGX-501 Падает TfgCollectionView под IOS (iOS). Исправлена ошибка открытия дизайнера формы в 13.1. При установке необходимо выбрать дизайнер для версии 13.1 В последних версиях iOS совместное использование TfgCollectionView и TfgLabel в режиме TfgTextType.HTML могло приводить к падениям.
  4. В вашем проекте по неизвестным мне причинам принудительно вы ставите одну и туже тему: procedure TFormMain.fgFormSystemAppearanceChanged(Sender: TObject; const AAppearance: TfgSystemAppearance); begin Application.ThemeSettings.ThemeKind := TfgThemeKind(2); end;Другими словами, вы выбираете тему через UI, применяете ее. затем получаете уведомление от формы, что тема поменялась и принудительно задаете тему TfgThemeKind(2)
  5. Прикрепите, пожалуйста, модифицированный проект. Сделал по вашему описанию модификацию проекта, но все работает, как ожидается. Тема при старте: Themes\Light\Green На устройстве для темной и светлой тем видно, что иконки меняют свой оттенок: При динамическом изменении заголовок, подзаголовок, добавлении кнопки со сменой иконки, внешний вид и оттенок не меняется.
  6. Changed Status to Fixed Changed Resolution to Fixed Changed Fix version to 1.19.6.0
  7. Да, проблема решена. Планируем выпустить релиз на следующей недели.
  8. При запуске с отладкой сразу поймал исключение с указанной причиной: Project BReceiver.apk raised exception class EJNIException with message 'java.lang.SecurityException: ru.fgx.breceiver: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts'.Соответственно нужно указать третьим параметром при регистрации ресивера TJContext.RECEIVER_EXPORTED / TJContext.RECEIVER_NOT_EXPORTED: TfgAndroidHelper.Context.registerReceiver(FReceiver, LIntentFilter, TJContext.RECEIVER_EXPORTED);
  9. Добавил эту строчку. Запускаю на Андроид 16 (правда 32-битную конфигурацию), полет нормальный. Ничего не виснет, приложение работает, при переключении авиарежима появляется тост. Если виснет, запустите приложение с отладкой. Либо сообщение об ошибке поймаете, либо смотрите системный лог.
  10. Changed Status to Fixed Changed Resolution to Fixed Changed Fix version to 1.19.6.0
  11. Hello, I have built new release with separated version of form designer for 13.1. Could you check on your side? Download link: https://disk.yandex.ru/d/LMUyJwrzU-znOg Thank you
  12. Добрый день, У нас нет кроссплатформенного компонента для этого. Но если нужно, то можно использовать Android API напрямую.
  13. Готового нет. Но можно использовать iOS API. UIDocumentPickerViewController

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.