ONO::FW::Apps::List

package ONO::FW::Apps::List;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################

use strict;

use ONO::IO;

use ONO::Render::Compress;

use ONO::Lib::UI::Check;

use ONO::FW::Apps::ToolBox;

###############################################################################
# list apps
###############################################################################

sub list {

my (
$self,
$db,
$community,
$lang,
$apps_ref,
$setup_ref,
$BLK_ref,
$vars_ref,
) = @_;

#: List / display app icons provided in an array.

my @apps = @$apps_ref;
my %setup = %$setup_ref;
my %BLK = %$BLK_ref;
my %vars = %$vars_ref;

my $APPS_BASE = ONO::FW::Apps::ToolBox->apps_base();

my ($WEB,$REL,$SIZE,$SIZE_STYLE,$TRANS,$trans,$FLOAT,$counter);

my $ID = 10000+int(rand(89999));

if ($setup{'cols'} < 1 || $setup{'cols'} > 10) {
$setup{'cols'} = 5;
}

if ($setup{'cols'} == 6) {
$FLOAT = " w50_1000i fl fn1000";
}

if ($setup{'nofollow'}) {
$REL = qq~ rel="nofollow"~;
}

if ($setup{'url_info'} !~ /\?/) {
$setup{'url_info'} .= "?app";
} else {
$setup{'url_info'} .= "&app";
}

if ($setup{'url_exec'} !~ /\?/) {
$setup{'url_exec'} .= "?app";
} else {
$setup{'url_exec'} .= "&app";
}

if ($setup{'url_info'} !~ /=$/) {
$setup{'url_info'} .= "=";
}
if ($setup{'url_exec'} !~ /=$/) {
$setup{'url_exec'} .= "=";
}

if (!$setup{'url_dev'}) {
$setup{'url_dev'} = $setup{'url_account'};
}
if (!$setup{'url_apps'}) {
$setup{'url_apps'} = $setup{'url_account'};
}

if ($setup{'fontclass'}) {
$setup{'fontclass'} = " $setup{'fontclass'}";
}

if ($setup{'fontstyle'}) {
$setup{'fontstyle'} = ";$setup{'fontstyle'}";
}

my $padding = "0px 10px 0px 10px";
if ($setup{'padding'}) {
$padding = $setup{'padding'};
}

my $loadsize = 128;
my $size = 128;
if ($setup{'size'} > 0 && $setup{'size'} < 257) {
$size = $setup{'size'};
if ($setup{'size'} > 128) {
$loadsize = 256;
}
if ($setup{'size'} < 65) {
$loadsize = 64;
}
}

my $colclass = " w20";
my $colstyle;
if ($setup{'cols'} && $setup{'cols'} != 5) {
my $width = int(10000/$setup{'cols'})/100;
$colclass = "";
$colstyle = ";width:${width}\%";
}

if ($size =~ /^(32|48|50|64|88|100|128|256)$/) {
$SIZE = $size;
} else {
$SIZE_STYLE = qq~ style="width:${size}px;height:${size}px"~;
}

if ($ENV{'HTTP_USER_AGENT'} =~ /(phone|android|ipad)/i) {
$setup{'fx_fadein'} = 0;
}

if ($setup{'fx_fadein'}) {
$trans = " trans10";
}

my $TABLE = "wide_table";
if ($setup{'align'} eq "left" && !$setup{'screen_size'}) {
$TABLE = "default_table";
}

if (!$vars{'app_view'} || $vars{'app_view'} eq "icons" || $vars{'app_view'} eq "ratings") {
$WEB .= qq~<div class="inline w100" style="padding:$padding">
<table class="$TABLE$FLOAT">
<tr class="vtop">
~;
}

foreach my $app (@apps) {
if ($app !~ /^#/) {

my $local_url;
if ($app =~ s/:(.*?)$//) {
$local_url = $1;
}

$app =~ s~[^a-z0-9\_\-]~~g;

my $info_ref = &info("",$community,$app,$lang);
my %info = %$info_ref;

if ((!$vars{'app_view'} || $vars{'app_view'} eq "icons" || $vars{'app_view'} eq "ratings") && $setup{'cols'} == 6 && $counter && $counter%3 == 0) {
$WEB .= qq~
</tr>
</table>
<table class="$TABLE$FLOAT">
<tr class="vtop">
~;
}

if ((!$vars{'app_view'} || $vars{'app_view'} eq "icons" || $vars{'app_view'} eq "ratings") && $counter%$setup{'cols'} == 0 && $counter > 1) {
$WEB .= qq~
</tr>
</table>
</div>
<div class="inline w100" style="padding:$padding">
<table class="$TABLE$FLOAT">
<tr class="vtop">
~;
}

$counter++;

$info{'icon'} =~ s~256~$loadsize~;

# standard apps

my $LINK = qq~$setup{'url_exec'}=$app~;
$LINK =~ s~==~=~g;
if (ONO::IO->exists("apps/$app/run")) {
$LINK = qq~/$APPS_BASE/$app/~;
if ($setup{'custom_link_base'}) {
$LINK = qq~$setup{'custom_link_base'}/$app/~;
}
} else {

# generate missing directories and files

ONO::IO->mkdir("apps");
ONO::IO->mkdir("apps/$app");
ONO::IO->mkdir("apps/$app/run");
ONO::IO->store("apps/$app/index.shtml", qq~<!--#include virtual="../../$setup{'url_info'}$app" -->~);
ONO::IO->store("apps/$app/run/index.shtml", qq~<!--#include virtual="../../../$setup{'url_exec'}$app" -->~);
}

# link to a fixed page on local server

if ($local_url) {
$LINK = $local_url;
}

# render the icon - icon view

if (!$vars{'app_view'} || $vars{'app_view'} eq "icons" || $vars{'app_view'} eq "ratings") {

my ($RANK,$ADD,$DELETE);
if ($vars{'app_view'} eq "ratings") {
$RANK = "<br>".&rank($community,$app,$setup{'url_info'},"c");
}
if ($setup{'app_add'}) {

my $SWITCH = ONO::Lib::UI::Check->switch("app_add_$app",0,"m");

$ADD = qq~<div class="box_green p0 auto inline" style="border:none">
<table class="default_table">
<tr>
<td class="p0">$SWITCH</td>
<td class="xsmall" style="padding-right:10px">$BLK{'add'}</td>
</tr>
</table>
</div>
~;
if ($setup{'app_add_hide'} =~ /:$app:/) {
$ADD = "";
}
}
if ($setup{'app_delete'}) {

my $SWITCH = ONO::Lib::UI::Check->switch("app_delete_$app",0,"m");

$DELETE = qq~<div class="box_red p0 auto inline" style="border:none">
<table class="default_table">
<tr>
<td class="p0">$SWITCH</td>
<td class="xsmall" style="padding-right:10px">$BLK{'remove'}</td>
</tr>
</table>
</div>
~;
}
if ($setup{'fx_fadein'} && $app && $app ne "-") {
my $fadein = 1+int($setup{'fx_fadein'}/2)+int(rand($setup{'fx_fadein'}/2));
$TRANS .= qq~onojs_gui_fx_fadein('app_td_${ID}_$app',10,$fadein,0);~;
}

if ($setup{'debug_app_name'}) {
$info{'title_en'} .= $setup{'debug_app_name'};
}

if (!$info{'title_en'} && ONO::IO->devstation) {
$info{'title_en'} = "$app name";
if (int(rand(10)) < 5) {
$info{'title_en'} = "$app name verylong";
}
}

my $title_img = $info{'title_en'};

my $small = "small";
if (length $info{'title_en'} > 12) {
$small = "xsmall";
}

if ($setup{"replace_name_$app"}) {
$info{'title_en'} = qq~<div class="lh125">$setup{"replace_name_$app"}</div>~;
}

$info{'title_en'} = qq~<span class="hide1000">$info{'title_en'}</span><span class="hide inline1000 $small">$info{'title_en'}</span>~;

my $link_color = "col3";
if ($setup{'label_color'}) {
$link_color = "col0";
my $STYLE = qq~ style="background-color:#$setup{'label_color'}"~;
my $CLASS;
if ($setup{'label_color'} eq "ffffff") {
$STYLE = "";
$CLASS = qq~ ono_app_label~;
}
$info{'title_en'} = qq~<div class="auto radius5 trans80$CLASS"$STYLE>
<div class="ono_app_label2">$info{'title_en'}</div>
</div>
~;
}

if (ONO::IO->devstation) {
$info{'icon'} = "/images/apps/apps_128.png";
}
if ($setup{"replace_icon_$app"}) {
$info{'icon'} = $setup{"replace_icon_$app"};
}

my $apptype = "app";
my $inset = " app${SIZE}_inset";
if ($setup{'app_shadow'} eq "dark") {
$apptype = "app_dark app";
}
if ($info{'icon'} =~ /\/collection_/) {
$apptype = "block";
$inset = "";
}

my ($RESP1,$RESP2);
if ($setup{'responsive_size'} && $setup{'responsive_trigger'}) {
$RESP1 = qq~ hide$setup{'responsive_trigger'}~;
$RESP2 = qq~<div class="auto block$setup{'responsive_size'} hide block$setup{'responsive_trigger'}">
<img class="$apptype$setup{'responsive_size'}" src="$setup{'host'}$info{'icon'}"$SIZE_STYLE alt="$title_img">
<div class="abs app$setup{'responsive_size'}_inset" style="top:0px"></div>
</div>
~;
}

my $APP;

if ($app ne "-") {

my $HEADER;
my $TITLE = qq~<a href="$LINK" class="$link_color$setup{'fontclass'}"$REL>$info{'title_en'}</a>~;

if ($setup{'title_header'}) {
$HEADER = qq~<$setup{'title_header'}>$info{'title_en'}</$setup{'title_header'}>~;
$TITLE = "";
}

my $rand = 1+int(rand(3));

$APP = qq~<a href="$LINK"$REL>
$HEADER
<div class="rel mb5 fadein${rand}s">
<div class="auto block$SIZE$RESP1">
<img class="$apptype$SIZE" src="$setup{'host'}$info{'icon'}"$SIZE_STYLE alt="$title_img">
<div class="abs$inset" style="top:0px"></div>
</div>
$RESP2
</div>
</a>
$TITLE$RANK$ADD$DELETE$setup{"inject_bottom_$app"}
~;

}

my $APP_TD;
if ($app && $app ne "-") {
$APP_TD = qq~ id="app_td_${ID}_$app"~;
}

$WEB .= qq~<td$APP_TD class="center$trans$colclass" style="padding:7px 0px 14px 0px$colstyle$setup{'fontstyle'};$setup{'td_style'}">$APP</td>~;

}

# render the icon - list view

if ($vars{'app_view'} eq "list") {

my $RANK = &rank($community,$app,$setup{'url_info'});

my $text;
if (ONO::IO->exists("var/community/$community/apps/$app/description_$lang.txt")) {
$text = ONO::IO->load("var/community/$community/apps/$app/description_$lang.txt");
} elsif (ONO::IO->exists("var/community/$community/apps/$app/description_en.txt")) {
$text = ONO::IO->load("var/community/$community/apps/$app/description_en.txt");
}

my $screenshot_width = int($size*1.923);

$WEB .= qq~<table class="wide_table bb">
<tr class="vtop">
<td>
<a href="$LINK"$REL><img class="app$size mr20" src="$info{'icon'}" alt=""></a>
</td>
<td class="w100">
<a href="/apps/$app/" class="button_yellow button_small" style="float:right"$REL>$BLK{'rate'}</a>
<a href="$setup{'url_account'}?community_screen=bookmarks&add=app_$app" class="button_green button_small" style="float:right"$REL>$BLK{'bookmark'}</a>
<a href="$LINK" class="button_green button_small" style="float:right"$REL>$BLK{'launch'}</a>
<h2 style="margin-bottom:5px"><a href="$LINK"$REL>$info{'title_en'}</a></h2>
$RANK
<span style="color:#999999">$text</span>
</td>
<td>
<a href="/apps/$app/"$REL><img class="block ml20" src="$info{'screenshot'}" style="width:${screenshot_width}px;height:${size}px" alt=""></a>
</td>
</tr>
</table>
~;
}

}
}

if ($TRANS) {
$TRANS = qq~<onload="$TRANS">~;
}

if (!$vars{'app_view'} || $vars{'app_view'} eq "icons" || $vars{'app_view'} eq "ratings") {
$WEB .= qq~ </tr>
</table>
</div>
$TRANS
~;
}

my $RETURN = $WEB;

if (!$setup{'align'}) {

if ($setup{'screen_size'} < 1 || $setup{'screen_size'} > 100) {
$setup{'screen_size'} = "90%";
}

$RETURN = qq~<div class="auto" style="width:$setup{'screen_size'}">$WEB</div>~;

} else {

if ($setup{'align'} eq "left") {

$RETURN = $WEB;

if ($setup{'screen_size'}) {
$RETURN = qq~<div style="width:$setup{'screen_size'}">$WEB</div>~;
}

}

if ($setup{'align'} eq "right") {
# not implemented
}

}

$RETURN = ONO::Render::Compress->compress($RETURN);
$RETURN =~ s~\<tr class="vtop"\>\</tr\>~\<tr class="vtop"\>\<td\>\</td\>\</tr\>~g;
return $RETURN;

}

sub rank {

my (
$community,
$app,
$url_info,
$switches,
) = @_;

#: App ranking helper.

my $rank = "XX";
if (ONO::IO->exists("var/community/$community/apps/$app/rank.txt")) {
$rank = int(ONO::IO->load("var/community/$community/apps/$app/rank.txt")/100000);
if (length $rank < 2) {
$rank = "0$rank";
}
}

my $margin = "margin-bottom:5px";
if ($switches =~ /c/) {
$margin = "margin:auto;margin-bottom:10px";
}

return qq~<a href="/apps/$app/"><img class="block" src="/ono/osr/images/rating/stars_$rank.gif" style="width:80px;height:16px;$margin" alt=""></a>~;

}

sub info {

my (
$self,
$community,
$app,
$lang,
) = @_;

#: App info helper.

my %info;

my @lines = ONO::IO->list("var/community/$community/apps/$app.txt");
foreach my $line (@lines) {
if ($line =~ m~^(.*?):(.*?):~) {
$info{$1} = $2;
}
}

if ($info{"title_$lang"}) {
$info{'title_en'} = $info{"title_$lang"};
}

return \%info;

}

###############################################################################
# end of script
###############################################################################

1;

__END__