Global: Implement showing platform

This commit is contained in:
veselcraft 2022-12-17 02:03:02 +03:00
parent 768f834ea1
commit 462d667e53
No known key found for this signature in database
GPG key ID: AED66BC1AC628A4E
23 changed files with 728 additions and 15 deletions

View file

@ -46,6 +46,7 @@ final class Account extends VKAPIRequestHandler
$this->requireUser(); $this->requireUser();
$this->getUser()->setOnline(time()); $this->getUser()->setOnline(time());
$this->getUser()->setClient_name($this->getPlatform());
$this->getUser()->save(); $this->getUser()->save();
return 1; return 1;

View file

@ -108,11 +108,31 @@ final class Users extends VKAPIRequestHandler
} }
break; break;
case "last_seen": case "last_seen":
if ($usr->onlineStatus() == 0) if ($usr->onlineStatus() == 0) {
$platform = $usr->getOnlinePlatform(true);
switch ($platform) {
case 'iphone':
$platform = 2;
break;
case 'android':
$platform = 4;
break;
case NULL:
$platform = 7;
break;
default:
$platform = 1;
break;
}
$response[$i]->last_seen = (object) [ $response[$i]->last_seen = (object) [
"platform" => 1, "platform" => $platform,
"time" => $usr->getOnline()->timestamp() "time" => $usr->getOnline()->timestamp()
]; ];
}
case "music": case "music":
$response[$i]->music = $usr->getFavoriteMusic(); $response[$i]->music = $usr->getFavoriteMusic();
break; break;

View file

@ -6,10 +6,12 @@ use openvk\Web\Models\Entities\User;
abstract class VKAPIRequestHandler abstract class VKAPIRequestHandler
{ {
protected $user; protected $user;
protected $platform;
function __construct(?User $user = NULL) function __construct(?User $user = NULL, ?string $platform = NULL)
{ {
$this->user = $user; $this->user = $user;
$this->platform = $platform;
} }
protected function fail(int $code, string $message): void protected function fail(int $code, string $message): void
@ -22,6 +24,11 @@ abstract class VKAPIRequestHandler
return $this->user; return $this->user;
} }
protected function getPlatform(): ?string
{
return $this->platform;
}
protected function userAuthorized(): bool protected function userAuthorized(): bool
{ {
return !is_null($this->getUser()); return !is_null($this->getUser());

View file

@ -64,6 +64,17 @@ final class Wall extends VKAPIRequestHandler
else else
$profiles[] = $attachment->getOwner()->getId(); $profiles[] = $attachment->getOwner()->getId();
$post_source = [];
if($attachment->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $attachment->getPlatform(true)
];
}
$repost[] = [ $repost[] = [
"id" => $attachment->getVirtualId(), "id" => $attachment->getVirtualId(),
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(), "owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
@ -72,13 +83,22 @@ final class Wall extends VKAPIRequestHandler
"post_type" => "post", "post_type" => "post",
"text" => $attachment->getText(false), "text" => $attachment->getText(false),
"attachments" => $repostAttachments, "attachments" => $repostAttachments,
"post_source" => [ "post_source" => $post_source,
"type" => "vk"
],
]; ];
} }
} }
$post_source = [];
if($attachment->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $attachment->getPlatform(true)
];
}
$items[] = (object)[ $items[] = (object)[
"id" => $post->getVirtualId(), "id" => $post->getVirtualId(),
"from_id" => $from_id, "from_id" => $from_id,
@ -94,7 +114,7 @@ final class Wall extends VKAPIRequestHandler
"is_archived" => false, "is_archived" => false,
"is_pinned" => $post->isPinned(), "is_pinned" => $post->isPinned(),
"attachments" => $attachments, "attachments" => $attachments,
"post_source" => (object)["type" => "vk"], "post_source" => $post_source,
"comments" => (object)[ "comments" => (object)[
"count" => $post->getCommentsCount(), "count" => $post->getCommentsCount(),
"can_post" => 1 "can_post" => 1
@ -212,6 +232,17 @@ final class Wall extends VKAPIRequestHandler
else else
$profiles[] = $attachment->getOwner()->getId(); $profiles[] = $attachment->getOwner()->getId();
$post_source = [];
if($attachment->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $attachment->getPlatform(true)
];
}
$repost[] = [ $repost[] = [
"id" => $attachment->getVirtualId(), "id" => $attachment->getVirtualId(),
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(), "owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
@ -220,13 +251,22 @@ final class Wall extends VKAPIRequestHandler
"post_type" => "post", "post_type" => "post",
"text" => $attachment->getText(false), "text" => $attachment->getText(false),
"attachments" => $repostAttachments, "attachments" => $repostAttachments,
"post_source" => [ "post_source" => $post_source,
"type" => "vk"
],
]; ];
} }
} }
$post_source = [];
if($post->getPlatform(true) === NULL) {
$post_source = (object)["type" => "vk"];
} else {
$post_source = (object)[
"type" => "api",
"platform" => $post->getPlatform(true)
];
}
$items[] = (object)[ $items[] = (object)[
"id" => $post->getVirtualId(), "id" => $post->getVirtualId(),
"from_id" => $from_id, "from_id" => $from_id,
@ -241,7 +281,7 @@ final class Wall extends VKAPIRequestHandler
"can_archive" => false, # TODO MAYBE "can_archive" => false, # TODO MAYBE
"is_archived" => false, "is_archived" => false,
"is_pinned" => $post->isPinned(), "is_pinned" => $post->isPinned(),
"post_source" => (object)["type" => "vk"], "post_source" => $post_source,
"attachments" => $attachments, "attachments" => $attachments,
"comments" => (object)[ "comments" => (object)[
"count" => $post->getCommentsCount(), "count" => $post->getCommentsCount(),
@ -384,6 +424,7 @@ final class Wall extends VKAPIRequestHandler
$post->setCreated(time()); $post->setCreated(time());
$post->setContent($message); $post->setContent($message);
$post->setFlags($flags); $post->setFlags($flags);
$post->setApi_Source_Name($this->getPlatform());
$post->save(); $post->save();
} catch(\LogicException $ex) { } catch(\LogicException $ex) {
$this->fail(100, "One of the parameters specified was missing or invalid"); $this->fail(100, "One of the parameters specified was missing or invalid");
@ -415,6 +456,7 @@ final class Wall extends VKAPIRequestHandler
$nPost->setOwner($this->user->getId()); $nPost->setOwner($this->user->getId());
$nPost->setWall($this->user->getId()); $nPost->setWall($this->user->getId());
$nPost->setContent($message); $nPost->setContent($message);
$nPost->setApi_Source_Name($this->getPlatform());
$nPost->save(); $nPost->save();
$nPost->attach($post); $nPost->attach($post);

View file

@ -23,6 +23,11 @@ class APIToken extends RowModel
return $this->getId() . "-" . chunk_split($this->getSecret(), 8, "-") . "jill"; return $this->getId() . "-" . chunk_split($this->getSecret(), 8, "-") . "jill";
} }
function getPlatform(): ?string
{
return $this->getRecord()->platform;
}
function isRevoked(): bool function isRevoked(): bool
{ {
return $this->isDeleted(); return $this->isDeleted();

View file

@ -114,6 +114,63 @@ class Post extends Postable
return $this->getOwner(false)->getId(); return $this->getOwner(false)->getId();
} }
function getPlatform(bool $forAPI = false): ?string
{
$platform = $this->getRecord()->api_source_name;
if($forAPI) {
switch ($platform) {
case 'openvk_android':
case 'openvk_legacy_android':
return 'android';
break;
case 'openvk_ios':
case 'openvk_legacy_ios':
return 'iphone';
break;
case 'vika_touch': // кика хохотач ахахахаххахахахахах
case 'vk4me':
return 'mobile';
break;
case NULL:
return NULL;
break;
default:
return 'api';
break;
}
} else {
return $platform;
}
}
function getPlatformDetails(): array
{
$clients = simplexml_load_file(OPENVK_ROOT . "/data/clients.xml");
foreach($clients as $client) {
if($client['tag'] == $this->getPlatform()) {
return [
"tag" => $client['tag'],
"name" => $client['name'],
"url" => $client['url'],
"img" => $client['img']
];
break;
}
}
return [
"tag" => $this->getPlatform(),
"name" => NULL,
"url" => NULL,
"img" => NULL
];
}
function pin(): void function pin(): void
{ {
DB::i() DB::i()

View file

@ -751,6 +751,63 @@ class User extends RowModel
return time() - $this->getRecord()->online <= 300; return time() - $this->getRecord()->online <= 300;
} }
function getOnlinePlatform(bool $forAPI = false): ?string
{
$platform = $this->getRecord()->client_name;
if($forAPI) {
switch ($platform) {
case 'openvk_android':
case 'openvk_legacy_android':
return 'android';
break;
case 'openvk_ios':
case 'openvk_legacy_ios':
return 'iphone';
break;
case 'vika_touch': // кика хохотач ахахахаххахахахахах
case 'vk4me':
return 'mobile';
break;
case NULL:
return NULL;
break;
default:
return 'api';
break;
}
} else {
return $platform;
}
}
function getOnlinePlatformDetails(): array
{
$clients = simplexml_load_file(OPENVK_ROOT . "/data/clients.xml");
foreach($clients as $client) {
if($client['tag'] == $this->getOnlinePlatform()) {
return [
"tag" => $client['tag'],
"name" => $client['name'],
"url" => $client['url'],
"img" => $client['img']
];
break;
}
}
return [
"tag" => $this->getOnlinePlatform(),
"name" => NULL,
"url" => NULL,
"img" => NULL
];
}
function prefersNotToSeeRating(): bool function prefersNotToSeeRating(): bool
{ {
return !((bool) $this->getRecord()->show_rating); return !((bool) $this->getRecord()->show_rating);

View file

@ -254,6 +254,7 @@ abstract class OpenVKPresenter extends SimplePresenter
$cacheTime = 0; # Force no cache $cacheTime = 0; # Force no cache
if($this->user->identity->onlineStatus() == 0 && !($this->user->identity->isDeleted() || $this->user->identity->isBanned())) { if($this->user->identity->onlineStatus() == 0 && !($this->user->identity->isDeleted() || $this->user->identity->isBanned())) {
$this->user->identity->setOnline(time()); $this->user->identity->setOnline(time());
$this->user->identity->setClient_name(NULL);
$this->user->identity->save(); $this->user->identity->save();
} }

View file

@ -195,10 +195,12 @@ final class VKAPIPresenter extends OpenVKPresenter
$identity = NULL; $identity = NULL;
} else { } else {
$token = (new APITokens)->getByCode($this->requestParam("access_token")); $token = (new APITokens)->getByCode($this->requestParam("access_token"));
if(!$token) if(!$token) {
$identity = NULL; $identity = NULL;
else } else {
$identity = $token->getUser(); $identity = $token->getUser();
$platform = $token->getPlatform();
}
} }
} }
@ -207,7 +209,7 @@ final class VKAPIPresenter extends OpenVKPresenter
if(!class_exists($handlerClass)) if(!class_exists($handlerClass))
$this->badMethod($object, $method); $this->badMethod($object, $method);
$handler = new $handlerClass($identity); $handler = new $handlerClass($identity, $platform);
if(!is_callable([$handler, $method])) if(!is_callable([$handler, $method]))
$this->badMethod($object, $method); $this->badMethod($object, $method);
@ -274,8 +276,11 @@ final class VKAPIPresenter extends OpenVKPresenter
$this->fail(28, "Invalid 2FA code", "internal", "acquireToken"); $this->fail(28, "Invalid 2FA code", "internal", "acquireToken");
} }
$platform = $this->requestParam("client_name");
$token = new APIToken; $token = new APIToken;
$token->setUser($user); $token->setUser($user);
$token->setPlatform(is_null($platform) ? "api" : $platform);
$token->save(); $token->save();
$payload = json_encode([ $payload = json_encode([

View file

@ -47,6 +47,11 @@
{else} {else}
<span>{$user->isFemale() ? tr("was_online_f") : tr("was_online_m")} {$user->getOnline()}</span> <span>{$user->isFemale() ? tr("was_online_f") : tr("was_online_m")} {$user->getOnline()}</span>
{/if} {/if}
{var $platform = $user->getOnlinePlatform()}
{var $platformDetails = $user->getOnlinePlatformDetails()}
<a n:if="!empty($platform)" class="client_app client_app_titlebar" data-app-tag="{$platform}" data-app-name="{$platformDetails['name']}" data-app-url="{$platformDetails['url']}" data-app-img="{$platformDetails['img']}">
<img src="/assets/packages/static/openvk/img/app_icons_mini/{$user->getOnlinePlatform(this)}.svg">
</a>
</div> </div>
<div n:if="$user->onlineStatus() == 2" style="float:right;"> <div n:if="$user->onlineStatus() == 2" style="float:right;">
<span><b>{_deceased_person}</b></span> <span><b>{_deceased_person}</b></span>

View file

@ -1,6 +1,8 @@
{var $author = $post->getOwner()} {var $author = $post->getOwner()}
{var $comments = $post->getLastComments(3)} {var $comments = $post->getLastComments(3)}
{var $commentsCount = $post->getCommentsCount()} {var $commentsCount = $post->getCommentsCount()}
{var $platform = $post->getPlatform()}
{var $platformDetails = $post->getPlatformDetails()}
{if $post->isDeactivationMessage() && $post->getText()} {if $post->isDeactivationMessage() && $post->getText()}
{var $deac = "post_deact"} {var $deac = "post_deact"}
{else} {else}
@ -83,6 +85,9 @@
</div> </div>
<div class="post-menu" n:if="!isset($compact)"> <div class="post-menu" n:if="!isset($compact)">
<a href="/wall{$post->getPrettyId()}" class="date">{$post->getPublicationTime()}</a> <a href="/wall{$post->getPrettyId()}" class="date">{$post->getPublicationTime()}</a>
<a n:if="!empty($platform)" class="client_app" data-app-tag="{$platform}" data-app-name="{$platformDetails['name']}" data-app-url="{$platformDetails['url']}" data-app-img="{$platformDetails['img']}">
<img src="/assets/packages/static/openvk/img/app_icons_mini/{$post->getPlatform(this)}.svg">
</a>
{if isset($thisUser)} {if isset($thisUser)}
&nbsp; &nbsp;

View file

@ -1,4 +1,6 @@
{var $author = $post->getOwner()} {var $author = $post->getOwner()}
{var $platform = $post->getPlatform()}
{var $platformDetails = $post->getPlatformDetails()}
{if $post->isDeactivationMessage() && $post->getText()} {if $post->isDeactivationMessage() && $post->getText()}
{var $deac = "post_deact"} {var $deac = "post_deact"}
{else} {else}
@ -46,6 +48,9 @@
<br/> <br/>
<a href="/wall{$post->getPrettyId()}" class="date"> <a href="/wall{$post->getPrettyId()}" class="date">
{$post->getPublicationTime()}{if $post->isPinned()}, {_pinned}{/if} {$post->getPublicationTime()}{if $post->isPinned()}, {_pinned}{/if}
<a n:if="!empty($platform)" class="client_app" data-app-tag="{$platform}" data-app-name="{$platformDetails['name']}" data-app-url="{$platformDetails['url']}" data-app-img="{$platformDetails['img']}">
<img src="/assets/packages/static/openvk/img/app_icons_mini/{$post->getPlatform(this)}.svg">
</a>
</a> </a>
</div> </div>
<div class="post-content" id="{$post->getPrettyId()}"> <div class="post-content" id="{$post->getPrettyId()}">

View file

@ -2216,6 +2216,17 @@ a.poll-retract-vote {
border-radius: 1px; border-radius: 1px;
} }
.client_app > img {
top: 3px;
position: relative;
}
.client_app.client_app_titlebar > img {
top: 2px;
position: relative;
filter: invert(100%) sepia(100%) saturate(800%) hue-rotate(2deg) brightness(130%) contrast(50.1%);
}
@keyframes appearing { @keyframes appearing {
from { from {
opacity: 0; opacity: 0;

BIN
Web/static/img/app_icons/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="13"
height="12"
viewBox="0 0 3.4395834 3.175"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:docname="android3.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:document-units="cm"
showgrid="false"
units="px"
height="41.5748px"
inkscape:zoom="81.919998"
inkscape:cx="5.6030275"
inkscape:cy="3.3142091"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:object-nodes="true" />
<defs
id="defs2">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath37304">
<path
id="path37306"
style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583"
d="m -1.208195,0.05994466 v 0.8536947 h 0.011369 0.010335 c 9.525e-4,-4.757e-5 0.0018,-1.9037e-4 0.00259,0 3.889e-4,-0.002058 0.00411,0 0.0062,0 h 0.010852 c 0.00848,-0.005343 0.011591,-0.006478 0.024288,-0.004651 9.843e-4,2.8575e-4 0.00211,2.5879e-4 0.0031,5.1594e-4 0.00234,-8.9694e-4 0.0077,-4.101e-4 0.010335,-5.1594e-4 0.00711,2.273e-5 0.014077,1.408e-5 0.021187,0 0.00677,-2.28e-5 0.013384,-3.81e-6 0.020154,0 0.00714,-1.66e-6 0.014564,-1.6e-7 0.021704,0 0.00477,3.2e-7 0.00918,3e-8 0.013953,0 h 0.014469 c 9.101e-4,-1.0771e-4 0.00536,-4.818e-5 0.00827,0 -6.853e-4,-4.363e-5 -7.038e-4,-4.445e-4 -0.00207,-5.1594e-4 0.0056,-0.003323 0.011823,-0.004677 0.018087,-0.005168 0.010439,-8.1756e-4 0.021763,0.001344 0.0320393,0.00155 0.008938,1.592e-4 0.0174199,-6.2442e-4 0.0263549,-5.1594e-4 0.006779,1.0192e-4 0.0138906,6.88e-6 0.0206706,0 0.005075,-3.7e-7 0.009911,1.06e-6 0.0149863,0 0.008078,-1.69e-6 0.01621,-1.3e-7 0.024288,0 h 0.0299723 0.0294556 c 0.0115597,-2.0775e-4 0.0150818,-1.8132e-4 0.0232545,0.005684 0.001302,-3.4661e-4 0.002787,-3.5454e-4 0.004134,-5.1594e-4 0.009007,-0.001082 0.0178197,-7.1173e-4 0.0268717,-5.1594e-4 0.0118994,4.0481e-4 0.0242689,4.818e-5 0.0361735,0 0.012287,2.323e-5 0.024403,2.41e-6 0.0366903,0 0.008969,0.001328 0.0217141,-0.001524 0.0304891,0 0.004907,8.5196e-4 0.009589,0.002109 0.0144693,0.003101 0.0202716,0.005682 0.0420467,0.00955 0.0630453,0.006718 0.019264,-0.001664 0.0385238,-5.715e-4 0.0578776,-5.1594e-4 0.0113678,-1.6364e-4 0.0227375,-1.317e-5 0.0341064,0 0.0217093,2.096e-5 0.0434032,9e-7 0.0651123,0 0.021019,1.99e-6 0.0420264,3.5e-7 0.0630452,0 0.026329,-3.2e-7 0.052736,-2e-8 0.0790649,0 h 0.063562 0.0764811 0.08319906 0.08940023 0.09198405 0.0868164 0.083199 c 0.004775,0 0.009727,-5.6356e-4 0.0144693,0 0.009292,0.001106 0.0181795,0.002985 0.0273885,0.004651 0.0202634,0.008023 0.0410901,0.00671 0.0620117,0.005168 v -0.868168 z M 0.37723795,1.3363526 c -0.0323437,0.00475 -0.064737,0.00932 -0.0971517,0.013436 0.004483,5.635e-4 0.008947,0.00103 0.0134358,0.00155 0.024294,0.00283 0.0484908,0.00519 0.0728638,0.00723 0.003614,8.02e-5 0.007237,3.492e-4 0.0108522,5.159e-4 z M -1.208195,1.405599 v 0.2397786 h 0.031523 c -0.0068,-0.00804 -0.011061,-0.018327 -0.010335,-0.032039 0.00141,-0.026685 0.025509,-0.046915 0.044442,-0.066663 -4.89e-5,-0.00911 0.0015,-0.019856 0.00465,-0.032039 0.00221,-0.00855 0.00827,-0.013763 0.01602,-0.01757 0.00162,-0.00552 0.00327,-0.011245 0.00517,-0.01757 -0.00484,-0.025418 -0.00871,-0.030086 0.0093,-0.029972 0.00103,-0.00113 0.00384,-0.00105 0.00775,0 0.00575,2.349e-4 0.012762,7.461e-4 0.021704,0.00103 0.00553,9.48e-5 0.011002,4.26e-4 0.016536,5.16e-4 -0.00132,-0.014832 -2.778e-4,-0.030044 0.00207,-0.044959 -0.015697,6.43e-4 -0.03133,0.00143 -0.047025,0.00207 -0.028246,0.00115 -0.056602,0.00624 -0.084749,0.00362 -0.00598,-5.582e-4 -0.011522,-0.0033 -0.017053,-0.0062 z M 0.34881593,1.48208 c -4.8419e-4,0.011645 -0.001095,0.023097 -0.001035,0.034623 0.009555,0.00225 0.0188897,0.00465 0.0294556,0.00723 V 1.482597 c -0.001537,-10e-5 -0.00306,-4.419e-4 -0.004651,-5.16e-4 -0.007902,-3.043e-4 -0.0158594,2.66e-5 -0.0237712,0 z M 0.24597982,1.528072 c -0.0145686,0.00173 -0.028946,0.00358 -0.0434082,0.00517 -5.4637e-4,0.00269 -9.3345e-4,0.00483 -0.00155,0.00775 0.011559,-8.09e-5 0.0230651,-3.625e-4 0.0346232,-5.159e-4 0.00258,-0.00459 0.00618,-0.00858 0.0103353,-0.012402 z" />
</clipPath>
</defs>
<g
inkscape:label="Слой 1"
inkscape:groupmode="layer"
id="layer1"
style="display:inline">
<rect
style="fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.546032;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect34329"
width="1.3066522"
height="0.89519173"
x="1.1048477"
y="1.3112783" />
<rect
style="fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.169924;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect34655"
width="0.11897118"
height="0.5640986"
x="1.2708721"
y="2.5055668" />
<rect
style="display:inline;fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.169924;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect34655-7"
width="0.11897118"
height="0.5640986"
x="1.2708721"
y="2.5055668" />
<rect
style="display:inline;fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.169924;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect34655-77"
width="0.11897118"
height="0.5640986"
x="2.0999825"
y="2.5055668" />
<rect
style="display:inline;fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.194942;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect34655-8-3"
width="0.11897118"
height="0.74242336"
x="0.41690901"
y="1.1351641" />
<rect
style="display:inline;fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.194942;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect34655-8-3-4"
width="0.11897118"
height="0.74242336"
x="2.9593756"
y="1.1416239" />
<ellipse
style="fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.158603;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="path36426"
clip-path="url(#clipPath37304)"
transform="matrix(1.1765277,0,0,1.1469176,2.2471522,-0.09130454)"
cy="0.85245097"
cx="-0.41533118"
rx="0.71396536"
ry="0.71345931" />
<circle
id="path37453"
style="fill:#b1bfcd;stroke:#b1bfcd;stroke-width:0.300027"
cx="0.21413387"
cy="-0.21969676"
rx="0.00042967169"
ry="0.00043080389" />
<path
style="fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.0742921;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0.82567734,0.95656447 1.86605516,3.202e-4"
id="path37509" />
<circle
style="fill:#ffffff;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.0737073;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="path49381"
cx="1.3264734"
cy="0.40012473"
rx="0.093269438"
ry="0.093515202" />
<circle
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.0737073;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="path49381-9"
cx="2.1689706"
cy="0.38728926"
rx="0.093269438"
ry="0.093515202" />
<rect
style="fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.0567164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect49512"
width="0.082897075"
height="0.24411611"
x="0.70749021"
y="0.74012035"
transform="matrix(0.76266423,-0.64679462,0.64481325,0.76434016,0,0)" />
<rect
style="display:inline;fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.0567164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="rect49512-4"
width="0.082917184"
height="0.24405694"
x="1.7347863"
y="-1.7031983"
transform="matrix(0.69963446,0.71450096,-0.71265767,0.70151197,0,0)" />
<ellipse
style="fill:#ffffff;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.08;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:stroke markers fill"
id="path858"
cx="1.3066671"
cy="0.3659997"
rx="0.082137227"
ry="0.086169124" />
<ellipse
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.08;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:stroke markers fill"
id="path858-3"
cx="2.1833293"
cy="0.37142435"
rx="0.082137227"
ry="0.086169124" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="13"
height="12"
viewBox="0 0 3.4395834 3.175"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:docname="app.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:document-units="cm"
showgrid="false"
units="px"
height="41.5748px"
inkscape:zoom="57.926187"
inkscape:cx="4.1949939"
inkscape:cy="6.8794447"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="false"
inkscape:lockguides="false" />
<defs
id="defs2" />
<g
inkscape:label="Слой 1"
inkscape:groupmode="layer"
id="layer1"
style="display:inline">
<circle
style="fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.56;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path11829"
cx="1.7356859"
cy="1.466198"
r="0.97289771" />
<rect
style="display:inline;fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.46;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013-4"
width="0.19183896"
height="0.1644334"
x="-2.2404912"
y="-1.0640687"
transform="rotate(-135)" />
<rect
style="display:inline;fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.46;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013-4-2"
width="0.19183896"
height="0.1644334"
x="-2.2501805"
y="1.2423611"
transform="rotate(-135)" />
<rect
style="display:inline;fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.46;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013-4-8"
width="0.19183896"
height="0.1644334"
x="-3.5406613"
y="0.10690999"
transform="rotate(-135)" />
<rect
style="display:inline;fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.46;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013-4-3"
width="0.19183896"
height="0.1644334"
x="-1.1922439"
y="0.10045043"
transform="rotate(-135)" />
<rect
style="fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.459999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013"
width="0.19183896"
height="0.1644334"
x="1.6580368"
y="0.29689372" />
<rect
style="display:inline;fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.459999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013-6"
width="0.19183896"
height="0.1644334"
x="2.7679622"
y="1.3291701" />
<rect
style="display:inline;fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.459999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013-2"
width="0.19183896"
height="0.1644334"
x="1.6580368"
y="2.4272633" />
<rect
style="display:inline;fill:none;fill-opacity:1;stroke:#b4c3d1;stroke-width:0.459999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect12013-5"
width="0.19183896"
height="0.1644334"
x="0.54624069"
y="1.3246025" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="13"
height="12"
viewBox="0 0 3.4395834 3.175"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:docname="apple.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:document-units="cm"
showgrid="false"
units="px"
height="41.5748px"
inkscape:zoom="81.919999"
inkscape:cx="5.6640626"
inkscape:cy="6.9396973"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="false"
inkscape:lockguides="false" />
<defs
id="defs2" />
<g
inkscape:label="Слой 1"
inkscape:groupmode="layer"
id="layer1"
style="display:inline">
<path
style="fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 1.3291067,1.0352556 C 1.3580953,1.0451798 1.8687503,0.76443557 1.8105126,0.53722663 1.7522756,0.3100176 1.621695,0.40133587 1.621695,0.40133587 c 0,0 -0.3093879,0.23521626 -0.2925883,0.63391973 z"
id="path1945" />
<path
style="fill:#b1bfcd;fill-opacity:1;stroke:#b1bfcd;stroke-width:0.065;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0.97396656,1.1195755 0.14048714,0.072757 0.1644335,0.022838 0.1827037,0.00914 0.1827038,-0.031973 0.1781362,-0.063946 0.1827038,-0.044014 0.1539604,0.00724 0.1020544,0.08088 0.075528,0.1039464 c 0.02427,0.054119 0.024692,0.093929 0.00591,0.1222167 l -0.058271,0.1012706 -0.080879,0.1134062 -0.078987,0.1141899 -0.04623,0.1362441 -0.013703,0.1233251 0.036541,0.095919 0.086784,0.1324602 0.1004871,0.1552982 0.045676,0.1278927 0.00914,0.1370278 -0.027406,0.1096223 c -0.025883,0.083323 -0.051766,0.1129373 -0.077649,0.1278926 L 2.1193331,2.9371552 1.9137914,2.9736962 1.7407683,2.9672366 1.6206731,2.894153 C 1.5765696,2.8621799 1.5404585,2.797909 1.4623746,2.7659359 c -0.054811,-0.010658 0.00847,-0.0084 -0.1289059,-0.019054 -0.066681,0.00329 -0.2291582,0.018753 -0.1634201,0.036865 0.231283,-0.096394 0.1105141,-0.1101151 -0.088906,0.067176 L 0.96261481,2.9312482 0.85299253,2.9699104 0.67241023,2.9758156 0.5206664,2.9417212 0.32559765,2.7923281 C 0.23756462,2.6934606 0.21200587,2.5973369 0.19258326,2.5215023 0.1637006,2.380765 0.16615923,2.3389987 0.14723193,2.2447711 0.13735317,2.1712436 0.13163511,2.0912566 0.12817787,2.0112696 l -0.002446,-0.1808118 c 0.0108463,-0.054849 -0.0112231,0.00221 0.0378786,-0.1827038 0.0192686,-0.047555 -0.0187052,0.00665 0.0692976,-0.1630956 0.0217224,-0.036948 0.0259959,-0.056447 0.0959195,-0.1415955 0.0378682,-0.031385 0.008225,-0.021224 0.14616303,-0.1141898 0.10598978,-0.062222 0.12681384,-0.063611 0.17813618,-0.086784 0.12977684,-0.03018 0.13969562,-0.030395 0.17112248,-0.035987 0.17440878,0.00449 0.1016276,0.00898 0.14971744,0.013473 z"
id="path8625"
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="13"
height="12"
viewBox="0 0 3.4395834 3.175"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:docname="mobile3.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:document-units="cm"
showgrid="false"
units="px"
height="41.5748px"
inkscape:zoom="64"
inkscape:cx="10.0625"
inkscape:cy="7.4453125"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Слой 1"
inkscape:groupmode="layer"
id="layer1"
style="display:inline">
<path
style="fill:#b4c3d1;fill-opacity:1;stroke:#b3c3d1;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 2.2844079,0.13500142 H 1.9097538 v 0.3100586 H 0.67597893 V 3.0482604 H 2.5944665 V 0.45497889 l -0.3067759,3e-8 z"
id="path968"
sodipodi:nodetypes="ccccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.148069;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.91868877,0.72209311 V 1.5567067 H 2.3520943 V 0.72209311 Z"
id="path10486" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.100298;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11110-4"
height="0.34838068"
x="1.8627164"
y="1.9218891"
width="0.44" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.101671;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11110-3"
width="0.45654547"
height="0.34838077"
x="1.86374"
y="2.5335131" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.101671;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11110-07"
width="0.45654535"
height="0.34838042"
x="0.91714829"
y="1.9186219" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.100298;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11110-9"
width="0.4442997"
height="0.34838066"
x="0.91569108"
y="2.5289454" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -122,3 +122,70 @@ u("#write > form").on("keydown", function(event) {
if(event.ctrlKey && event.keyCode === 13) if(event.ctrlKey && event.keyCode === 13)
this.submit(); this.submit();
}); });
var tooltipClientTemplate = Handlebars.compile(`
<table>
<tr>
<td width="54" valign="top">
<img src="{{img}}" width="54" />
</td>
<td width="1"></td>
<td width="150" valign="top">
<text>
{{app_tr}}: <b>{{name}}</b>
</text><br/>
<a href="{{url}}">Подробнее</a>
</td>
</tr>
</table>
`);
var tooltipClientNoInfoTemplate = Handlebars.compile(`
<table>
<tr>
<td width="150" valign="top">
<text>
{{app_tr}}: <b>{{name}}</b>
</text><br/>
</td>
</tr>
</table>
`);
tippy(".client_app", {
theme: "light vk",
content: "⌛",
allowHTML: true,
interactive: true,
interactiveDebounce: 500,
onCreate: async function(that) {
that._resolvedClient = null;
},
onShow: async function(that) {
let client_tag = that.reference.dataset.appTag;
let client_name = that.reference.dataset.appName;
let client_url = that.reference.dataset.appUrl;
let client_img = that.reference.dataset.appImg;
if(client_name != "") {
let res = {
'name': client_name,
'url': client_url,
'img': client_img,
'app_tr': tr("app")
};
that.setContent(tooltipClientTemplate(res));
} else {
let res = {
'name': client_tag,
'app_tr': tr("app")
};
that.setContent(tooltipClientNoInfoTemplate(res));
}
}
});

5
data/clients.xml Normal file
View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Clients name="standard">
<Client tag="vk4me" name="VK4ME" url="http://vk4me.crx.moe/" img="/assets/packages/static/openvk/img/app_icons/vk4me.png" />
<Client tag="openvk_legacy_android" name="OpenVK Legacy" url="https://f-droid.org/ru/packages/uk.openvk.android.legacy/" img="/assets/packages/static/openvk/img/app_icons/openvk_legacy.png" />
</Clients>

View file

@ -0,0 +1,8 @@
ALTER TABLE `profiles`
ADD COLUMN `client_name` TEXT NULL DEFAULT NULL AFTER `backdrop_2`;
ALTER TABLE `posts`
ADD COLUMN `api_source_name` TEXT NULL DEFAULT NULL AFTER `anonymous`;
ALTER TABLE `api_tokens`
ADD COLUMN `platform` TEXT NULL DEFAULT NULL AFTER `deleted`;