diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81462bb5c..5f5028741 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ v0.30 (master)
* Add Stories status on the avatars
* Add support of several simultanous Muji invites in MUC chatrooms
* Important color management CSS cleanup
+* Add Accent Color in the Configuration
v0.29.2
---------------------------
diff --git a/app/MujiCallParticipant.php b/app/MujiCallParticipant.php
index 6a8d4d8a4..b5c2eed51 100644
--- a/app/MujiCallParticipant.php
+++ b/app/MujiCallParticipant.php
@@ -27,6 +27,19 @@ class MujiCallParticipant extends Model
->where('session_id', $this->session_id);
}
+ public function getMeAttribute(): bool
+ {
+ $jid = explodeJid($this->jid);
+
+ if ($jid['resource'] == null) {
+ return $this->jid == \App\User::me()->id;
+ }
+
+ $presence = Presence::where('jid', $jid['jid'])->where('resource', $jid['resource'])->first();
+
+ return $presence && $presence->mucjid == \App\User::me()->id;
+ }
+
public function getNameAttribute()
{
return explodeJid($this->jid)['resource'];
diff --git a/app/User.php b/app/User.php
index 7f7e3b58e..08e414208 100644
--- a/app/User.php
+++ b/app/User.php
@@ -12,7 +12,7 @@ class User extends Model
{
protected $fillable = [
'id', 'language', 'nightmode', 'chatmain', 'nsfw', 'nickname',
- 'notificationchat', 'notificationcall', 'omemoenabled'
+ 'notificationchat', 'notificationcall', 'omemoenabled', 'accentcolor'
];
public $with = ['session', 'capability'];
protected $keyType = 'string';
@@ -197,6 +197,10 @@ class User extends Model
$this->language = (string)$config['language'];
}
+ if (isset($config['accentcolor'])) {
+ $this->accentcolor = (string)$config['accentcolor'];
+ }
+
if (isset($config['nsfw'])) {
$this->nsfw = (bool)$config['nsfw'];
}
diff --git a/app/Widgets/Chat/_chat.tpl b/app/Widgets/Chat/_chat.tpl
index 4620f02e6..345b2d6d2 100644
--- a/app/Widgets/Chat/_chat.tpl
+++ b/app/Widgets/Chat/_chat.tpl
@@ -32,7 +32,7 @@
presence && $conference->presence->mucrole == 'visitor'"}disabled{/if}">
-
+
expand_more
+
+
+ palette
+
+
+
{$c->__('config.accent_color')}
+
+
+ {loop="$accent_colors"}
+ {autoescape="off"}{$c->prepareAccentColorRadio($value)}{/autoescape}
+ {/loop}
+
+
+
diff --git a/app/Widgets/Config/config.css b/app/Widgets/Config/config.css
index dd820d316..aeddb4b2b 100644
--- a/app/Widgets/Config/config.css
+++ b/app/Widgets/Config/config.css
@@ -6,4 +6,17 @@ form div > span.supporting.night_mode_detected {
form div > span.supporting.night_mode_detected {
display: initial;
}
+}
+
+form li#accent_color div.radio {
+ display: inline-block;
+ margin-right: 0.5rem;
+}
+
+form li#accent_color div.radio label {
+ transform: scale(1.5);
+}
+
+form li#accent_color > div {
+ height: 9rem;
}
\ No newline at end of file
diff --git a/app/Widgets/Config/config.js b/app/Widgets/Config/config.js
index 0f538c1fd..0705562bb 100644
--- a/app/Widgets/Config/config.js
+++ b/app/Widgets/Config/config.js
@@ -1,15 +1,18 @@
var Config = {
- switchNightMode: function()
- {
+ switchNightMode: function () {
document.body.classList.toggle('nightmode');
},
+ setAccentColor: function (color) {
+ document.body.style.setProperty('--movim-accent', 'var(--p-' + color + ')');
+ },
+
updateSystemVariable: function (variable, value) {
window[variable] = value;
}
}
-MovimWebsocket.attach(function() {
+MovimWebsocket.attach(function () {
Notif.current('conf');
Config_ajaxMAMGetConfig();
diff --git a/app/Widgets/Config/locales.ini b/app/Widgets/Config/locales.ini
index fdc5f748c..1810a7245 100644
--- a/app/Widgets/Config/locales.ini
+++ b/app/Widgets/Config/locales.ini
@@ -30,4 +30,5 @@ blog_saved = Personal blog confidentiality saved
confidentiality = Confidentiality
audio_title = Audio notifications
audio_call = Incoming call
-audio_chat = Incoming message
\ No newline at end of file
+audio_chat = Incoming message
+accent_color = Accent color
\ No newline at end of file
diff --git a/app/Widgets/Drawer/drawer.css b/app/Widgets/Drawer/drawer.css
index 80c169d69..ffaf9a647 100644
--- a/app/Widgets/Drawer/drawer.css
+++ b/app/Widgets/Drawer/drawer.css
@@ -5,7 +5,7 @@
left: 0;
width: 100%;
max-height: calc(100% - 7rem);
- box-shadow: var(--elevation-3);
+ box-shadow: var(--elevation-5);
transition: transform .3s ease-in-out;
display: flex;
flex-direction: column;
@@ -35,3 +35,12 @@
left: calc(50% - 35rem);
}
}
+
+
+#drawer ul.list>li.search form div:after {
+ background-color: rgb(var(--movim-background));
+}
+
+#drawer ul.list>li.search form div:focus-within:after {
+ background-color: rgba(var(--movim-background), 0.8);
+}
\ No newline at end of file
diff --git a/app/Widgets/Rooms/Rooms.php b/app/Widgets/Rooms/Rooms.php
index 88d56655b..8574b1f7a 100644
--- a/app/Widgets/Rooms/Rooms.php
+++ b/app/Widgets/Rooms/Rooms.php
@@ -74,7 +74,7 @@ class Rooms extends Base
{
$muji = $packet->content;
- if ($muji->jidfrom && $muji->conference) {
+ if ($muji->jidfrom && $muji->conference && !$muji->inviter->me) {
Notif::append(
'chat|' . $muji->jidfrom,
($muji->conference != null && $muji->conference->name)
@@ -85,7 +85,9 @@ class Rooms extends Base
: "📞 " . __('muji.call_audio_invite'),
$muji->conference->getPicture(),
5,
- $this->route('chat', [$muji->jidfrom, 'room'])
+ $this->route('chat', [$muji->jidfrom, 'room']),
+ null,
+ 'Search.chat(\'' . echapJS($muji->jidfrom) . '\', true)'
);
$this->onCallInvite($packet);
@@ -147,9 +149,11 @@ class Rooms extends Base
public function onBookmarkGet($packet)
{
- foreach ($this->user->session->conferences()
- ->where('bookmarkversion', (int)$packet->content)
- ->get() as $room) {
+ foreach (
+ $this->user->session->conferences()
+ ->where('bookmarkversion', (int)$packet->content)
+ ->get() as $room
+ ) {
if ($room->autojoin && !$room->connected) {
$this->ajaxJoin($room->conference, $room->nick);
}
@@ -181,7 +185,7 @@ class Rooms extends Base
$composing
? 'MovimUtils.addClass'
: 'MovimUtils.removeClass',
- '#' . cleanupId($room.'_rooms_primary'),
+ '#' . cleanupId($room . '_rooms_primary'),
'composing'
);
}
@@ -189,15 +193,15 @@ class Rooms extends Base
private function setCounter(string $room)
{
$conference = $this->user->session
- ->conferences()
- ->where('conference', $room)
- ->withCount('unreads', 'quoted')
- ->first();
+ ->conferences()
+ ->where('conference', $room)
+ ->withCount('unreads', 'quoted')
+ ->first();
if ($conference) {
$this->rpc(
'MovimTpl.fill',
- '#' . cleanupId($room.'_rooms_primary'),
+ '#' . cleanupId($room . '_rooms_primary'),
$this->prepareRoomCounter($conference, $conference->getPicture())
);
@@ -209,10 +213,10 @@ class Rooms extends Base
public function onPresence(string $room, bool $callSecond = true)
{
$conference = $this->user->session->conferences()
- ->where('conference', $room)
- ->with('info', 'contact', 'presence')
- ->withCount('unreads', 'quoted', 'presences')
- ->first();
+ ->where('conference', $room)
+ ->with('info', 'contact', 'presence')
+ ->withCount('unreads', 'quoted', 'presences')
+ ->first();
if ($conference) {
$this->rpc('Rooms.setRoom', \cleanupId($conference->conference), $this->prepareConference($conference), $callSecond);
@@ -227,9 +231,9 @@ class Rooms extends Base
public function ajaxHttpGet()
{
$conferences = $this->user->session->conferences()
- ->with('info', 'contact', 'presence')
- ->withCount('unreads', 'quoted', 'presences')
- ->get();
+ ->with('info', 'contact', 'presence')
+ ->withCount('unreads', 'quoted', 'presences')
+ ->get();
$this->rpc('Rooms.clearRooms');
@@ -258,7 +262,7 @@ class Rooms extends Base
$r = new Request;
$r->setTo($room)
- ->request();
+ ->request();
$p = new Muc;
$p->setTo($room);
@@ -269,8 +273,8 @@ class Rooms extends Base
$jid = explodeJid($room);
$capability = \App\Info::where('server', $jid['server'])
- ->where('node', '')
- ->first();
+ ->where('node', '')
+ ->first();
if ($capability && ($capability->isMAM() || $capability->isMAM2())) {
$this->rpc('MovimUtils.addClass', '#chat_widget .contained', 'loading');
@@ -283,12 +287,12 @@ class Rooms extends Base
} else {
$r = new Request;
$r->setTo($jid['server'])
- ->request();
+ ->request();
}
$m = new GetMembers;
$m->setTo($room)
- ->request();
+ ->request();
$p->setNickname($nickname);
$p->request();
@@ -319,8 +323,8 @@ class Rooms extends Base
$jid = explodeJid($room);
$capability = \App\Info::where('server', $jid['server'])
- ->where('node', '')
- ->first();
+ ->where('node', '')
+ ->first();
if (!$capability || !$capability->isMAM()) {
$this->user->messages()->where('jidfrom', $room)->delete();
@@ -331,19 +335,19 @@ class Rooms extends Base
// We clear the presences from the buffer cache and then the DB
$this->user->session->conferences()
- ->where('conference', $room)
- ->first()->presences()->delete();
+ ->where('conference', $room)
+ ->first()->presences()->delete();
$this->ajaxHttpGet();
if ($resource) {
$session = Session::instance();
- $session->delete($room . '/' .$resource);
+ $session->delete($room . '/' . $resource);
$pu = new Unavailable;
$pu->setTo($room)
- ->setResource($resource)
- ->request();
+ ->setResource($resource)
+ ->request();
}
}
diff --git a/app/Widgets/Visio/visio.css b/app/Widgets/Visio/visio.css
index 5c5ed6fd4..467ff66fd 100644
--- a/app/Widgets/Visio/visio.css
+++ b/app/Widgets/Visio/visio.css
@@ -198,7 +198,7 @@ body>#visio:not(:fullscreen) .participant img.avatar {
position: absolute;
width: 100%;
z-index: 1;
- background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.8), transparent);
+ background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.4), transparent);
}
#visio header ul.list li {
@@ -225,6 +225,8 @@ body>#visio:not(:fullscreen) .participant img.avatar {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
+ color: white;
+ opacity: 0.6;
}
#visio .button.action {
@@ -278,8 +280,11 @@ body>#visio:not(:fullscreen) #participants .participant:not(.active) {
/** Grid view **/
-#visio #participants:not(.active) .participant.active {
- background-color: rgba(var(--movim-font), 0.1);
+#visio #participants:not(.active) .participant.active:not(.audio_off)::after {
+ color: var(--p-green);
+ opacity: calc(1 - var(--level));
+ transform: scale(1.5) translateX(0.25rem) translateY(-0.25rem);
+ transition: opacity 0.5s ease-in-out, transform .3s cubic-bezier(.4,0,.2,1);
}
#visio #participants:not(.active):has(.participant:nth-child(2)) .participant {
@@ -324,6 +329,7 @@ body>#visio #participants:not(.active):has(.participant:nth-child(7)) .participa
color: white;
text-shadow: 0 0 1rem rgba(0, 0, 0, 0.85);
font-size: 2rem;
+ transition: opacity 0.5s ease-in-out, transform .3s cubic-bezier(.4,0,.2,1);
}
#visio .participant::after {
diff --git a/app/Widgets/Visio/visio.tpl b/app/Widgets/Visio/visio.tpl
index d68d86092..4f89b33f6 100644
--- a/app/Widgets/Visio/visio.tpl
+++ b/app/Widgets/Visio/visio.tpl
@@ -2,30 +2,30 @@
-
-
+
back_to_tab
-
+
fullscreen
-
+
tile_small
-
+
dialpad
-
+
mic
-
+
videocam
-
+
switch_camera
-
+
screen_share
diff --git a/database/migrations/20250331170107_add_accent_color_to_users_table.php b/database/migrations/20250331170107_add_accent_color_to_users_table.php
new file mode 100644
index 000000000..a81f6f623
--- /dev/null
+++ b/database/migrations/20250331170107_add_accent_color_to_users_table.php
@@ -0,0 +1,21 @@
+schema->table('users', function (Blueprint $table) {
+ $table->string('accentcolor')->default('dorange');
+ });
+ }
+
+ public function down()
+ {
+ $this->schema->table('users', function (Blueprint $table) {
+ $table->dropColumn('accentcolor');
+ });
+ }
+}
diff --git a/public/scripts/movim_visio.js b/public/scripts/movim_visio.js
index bbb0036f9..71697902c 100644
--- a/public/scripts/movim_visio.js
+++ b/public/scripts/movim_visio.js
@@ -272,20 +272,20 @@ var MovimVisio = {
}
if (MovimVisio.localAudio) {
- let localStream = MovimVisio.localAudio.srcObject;
+ let stream = MovimVisio.localAudio.srcObject;
- if (localStream) {
- localStream.getTracks().forEach(track => track.stop());
- localStream = null;
+ if (stream) {
+ stream.getTracks().forEach(track => track.stop());
+ stream = null;
}
}
if (MovimVisio.localVideo) {
- let localStream = MovimVisio.localVideo.srcObject;
+ let stream = MovimVisio.localVideo.srcObject;
- if (localStream) {
- localStream.getTracks().forEach(track => track.stop());
- localStream = null;
+ if (stream) {
+ stream.getTracks().forEach(track => track.stop());
+ stream = null;
}
}
diff --git a/public/theme/css/color.css b/public/theme/css/color.css
index cb70d90ca..73c846aa7 100644
--- a/public/theme/css/color.css
+++ b/public/theme/css/color.css
@@ -1,7 +1,6 @@
/* Color */
body {
- --movim-accent: var(--p-dorange);
--movim-background-main: 255, 255, 255;
--movim-background: 238, 238, 238;
--movim-gray: 35, 35, 35;
@@ -34,8 +33,9 @@ body.nightmode {
}
}
-body {
- background-color: rgb(var(--movim-background));
+body,
+.drawer {
+ background-color: rgb(var(--movim-background-main));
}
body > *,
@@ -67,7 +67,7 @@ table tr th {
}
ul li.date > div > p.normal,
-.dialog, .drawer, ul.context_menu,
+.dialog, ul.context_menu,
.card > .block:not(.subheader):not(.simple) {
background-color: rgb(var(--movim-background-main));
}
@@ -90,8 +90,13 @@ form > div .radio > input[type="radio"]:checked + label {
color: white;
}
+span.icon span.counter:not(.alt) {
+ color: white;
+}
+
span.icon span.counter.alt {
- background-color: var(--movim-accent);
+ color: var(--movim-font);
+ background-color: rgb(var(--movim-background-main));
}
/* Elements */
@@ -154,7 +159,7 @@ span.icon:not(.composing):not([data-counter]):not(.story).status.server_error:af
.color.steam,
.color.bgray { color: white; background-color: var(--p-bgray); border-color: var(--p-bgray) }
-.color.transparent { color: white; backdrop-filter: blur(1rem); background-color: rgba(0, 0, 0, 0.25); }
+.color.none { color: white; background-color: transparent; }
.color.semi { color: rgba(var(--movim-font), 0.87); background-color: rgba(var(--movim-background-main), 0.75); }
form > div > input:focus:invalid,
diff --git a/public/theme/css/form.css b/public/theme/css/form.css
index 707eb9ea2..66c3069bd 100644
--- a/public/theme/css/form.css
+++ b/public/theme/css/form.css
@@ -257,8 +257,8 @@ form > div .radio > input[type="radio"] + label {
border-style: solid;
border-color: gray;
transition: box-shadow 0.1s ease;
- margin: 1.25rem;
- margin-bottom: 0;
+ margin: 0 1.25rem;
+ position: relative;
}
form > div .radio > input[type="radio"] + label:hover {
diff --git a/public/theme/css/notification.css b/public/theme/css/notification.css
index 5b7f2c1a2..a4d0fba14 100644
--- a/public/theme/css/notification.css
+++ b/public/theme/css/notification.css
@@ -11,7 +11,7 @@
color: white;
box-sizing: border-box;
pointer-events: none;
- transition: opacity 0.2s ease, transform 0.4s ease;
+ transition: opacity 0.2s ease, transform 0.4s ease, box-shadow .3s cubic-bezier(.4,0,.2,1);
background-color: rgb(var(--movim-gray));
transform: translateY(0);
}
@@ -35,6 +35,10 @@
top: 1rem;
}
+.snackbar:hover {
+ box-shadow: var(--elevation-4);
+}
+
.toast {
left: calc(50% - 24rem);
line-height: 2.5rem;
diff --git a/public/theme/css/style.css b/public/theme/css/style.css
index 72194ca20..963644b5d 100644
--- a/public/theme/css/style.css
+++ b/public/theme/css/style.css
@@ -77,7 +77,7 @@ body>div.dialog:not(:empty)~main,
body>div.dialog:not(:empty)~nav,
body>div.dialog:not(:empty)~#visio,
body>nav.active~main {
- opacity: 0.15;
+ opacity: 0.05;
pointer-events: none;
}
diff --git a/src/Moxl/Xec/Payload/MAMResult.php b/src/Moxl/Xec/Payload/MAMResult.php
index a07a9f356..137922d7e 100644
--- a/src/Moxl/Xec/Payload/MAMResult.php
+++ b/src/Moxl/Xec/Payload/MAMResult.php
@@ -18,7 +18,7 @@ class MAMResult extends Payload
$stanza->forwarded->delay
&& isset($stanza->attributes()->queryid)
&& $messagesCounter >= 0
- ) {\logDebug($stanza->asXML());
+ ) {
$session->set('mamid' . (string)$stanza->attributes()->queryid, $messagesCounter + 1);
if ($stanza->forwarded->message->retract