diff --git a/qtcnet-client/Forms/MainForm.Designer.cs b/qtcnet-client/Forms/MainForm.Designer.cs index 95fd610..d200ff8 100644 --- a/qtcnet-client/Forms/MainForm.Designer.cs +++ b/qtcnet-client/Forms/MainForm.Designer.cs @@ -28,8 +28,43 @@ /// private void InitializeComponent() { + components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + niMain = new NotifyIcon(components); + ctxNotifyIcon = new ContextMenuStrip(components); + tsiShow = new ToolStripMenuItem(); + tsiExit = new ToolStripMenuItem(); + ctxNotifyIcon.SuspendLayout(); SuspendLayout(); // + // niMain + // + niMain.ContextMenuStrip = ctxNotifyIcon; + niMain.Icon = (Icon)resources.GetObject("niMain.Icon"); + niMain.Text = "QtC.NET"; + niMain.Visible = true; + niMain.DoubleClick += niMain_DoubleClick; + // + // ctxNotifyIcon + // + ctxNotifyIcon.Items.AddRange(new ToolStripItem[] { tsiShow, tsiExit }); + ctxNotifyIcon.Name = "ctxNotifyIcon"; + ctxNotifyIcon.Size = new Size(104, 48); + // + // tsiShow + // + tsiShow.Name = "tsiShow"; + tsiShow.Size = new Size(103, 22); + tsiShow.Text = "Show"; + tsiShow.Click += tsiShow_Click; + // + // tsiExit + // + tsiExit.Name = "tsiExit"; + tsiExit.Size = new Size(103, 22); + tsiExit.Text = "Exit"; + tsiExit.Click += tsiExit_Click; + // // MainForm // AutoScaleDimensions = new SizeF(7F, 15F); @@ -45,9 +80,15 @@ Load += MainForm_Load; Paint += MainForm_Paint; Resize += MainForm_Resize; + ctxNotifyIcon.ResumeLayout(false); ResumeLayout(false); } #endregion + + private NotifyIcon niMain; + private ContextMenuStrip ctxNotifyIcon; + private ToolStripMenuItem tsiShow; + private ToolStripMenuItem tsiExit; } } diff --git a/qtcnet-client/Forms/MainForm.cs b/qtcnet-client/Forms/MainForm.cs index ce81d54..fa86b5d 100644 --- a/qtcnet-client/Forms/MainForm.cs +++ b/qtcnet-client/Forms/MainForm.cs @@ -45,12 +45,12 @@ namespace qtcnet_client private readonly UpdateService _updateService; private readonly AudioService _audioService; - public MainForm(IApiService apiService, - IGatewayService gatewayService, - LoggingService loggingService, - CredentialService credentialService, - ClientConfig config, - ImageFactory imageFactory, + public MainForm(IApiService apiService, + IGatewayService gatewayService, + LoggingService loggingService, + CredentialService credentialService, + ClientConfig config, + ImageFactory imageFactory, UpdateService updateService, AudioService audioService) { @@ -74,7 +74,7 @@ namespace qtcnet_client Graphics g = e.Graphics; Rectangle _formRect = ClientRectangle; - if (_formRect.IsEmpty) + if (_formRect.IsEmpty) _formRect = e.ClipRectangle; // draw gradient background @@ -82,7 +82,13 @@ namespace qtcnet_client g.FillRectangle(b, _formRect); } - private void MainForm_Resize(object sender, EventArgs e) => Invalidate(); + private void MainForm_Resize(object sender, EventArgs e) + { + if (WindowState == FormWindowState.Minimized && _config.MinimizeToTray) + Hide(); + + Invalidate(); + } private async void MainForm_Load(object sender, EventArgs e) { @@ -145,7 +151,7 @@ namespace qtcnet_client Controls.Remove(LoginControl); LoginControl?.Dispose(); LoginControl = null; - + // create register control RegisterControl = new() { @@ -247,7 +253,7 @@ namespace qtcnet_client { if (sender is RoomControl _roomCtrl) { - if(OpenChatRoomForms.Count > 0) + if (OpenChatRoomForms.Count > 0) { KryptonMessageBox.Show("Joining Multiple Rooms Is Currently Unsupported.", ":("); return; @@ -346,12 +352,12 @@ namespace qtcnet_client private async void MainTabControl_OnUserItemDoubleClicked(object? sender, EventArgs e) { - if(sender is MainTabControl _mtCtrl) + if (sender is MainTabControl _mtCtrl) { - if(_mtCtrl.SelectedUser != null) + if (_mtCtrl.SelectedUser != null) { // get the user to open the profile for - if(_mtCtrl.SelectedUser.Tag is string _tagString) + if (_mtCtrl.SelectedUser.Tag is string _tagString) { var _user = await _apiService.GetUserInformationAsync(_tagString); if (_user.Success && _user.Data != null) @@ -421,7 +427,7 @@ namespace qtcnet_client private void _gatewayService_OnServerConfigReceived(object? sender, EventArgs e) { - if(e is ServerConfigEventArgs _args) + if (e is ServerConfigEventArgs _args) { if (InvokeRequired) Invoke(() => Text = $"{Text} - Connected To {_args.ServerConfig.Name}"); @@ -438,7 +444,8 @@ namespace qtcnet_client UserContactsList.Clear(); UserContactsList.AddRange([.. _currentUserContacts.Data.DistinctBy(c => c.Id)]); await SetupContactsUI(_currentUserContacts.Data); - } else + } + else { // if no contacts are found, just clear the lists UserContactsList.Clear(); @@ -464,9 +471,9 @@ namespace qtcnet_client private async void _gatewayService_OnServerDisconnect(object? sender, EventArgs e) { - if(e is ServerConnectionClosedEventArgs _args) + if (e is ServerConnectionClosedEventArgs _args) { - if(_args.Error != null) + if (_args.Error != null) { Reconnect: // probably not the best idea to use labels but whatever var _dialogRes = KryptonMessageBox.Show($"Connection To The Server Lost. Would You Like To Try Again?\n\nError - {_args.Error?.Message}", "Uh Oh.", @@ -638,11 +645,15 @@ namespace qtcnet_client ResumeLayout(true); + // minimize main window if start minimized is on + if (_config.StartMinimized) + WindowState = FormWindowState.Minimized; + // check for daily spin eligibility var now = DateTime.UtcNow; var lastSpin = _apiService.CurrentUser.LastCurrencySpin; - if(lastSpin.Date < now.Date) + if (lastSpin.Date < now.Date) { Random rnd = new(); @@ -651,7 +662,7 @@ namespace qtcnet_client CurrencyWon = rnd.Next(0, 200) }; var _dialogRes = _jackpotSpin.ShowDialog(); - if(_dialogRes == DialogResult.OK) + if (_dialogRes == DialogResult.OK) { // claim var _apiRes = await _apiService.AddCurrencyToCurrentUser(_jackpotSpin.CurrencyWon, true); @@ -673,11 +684,11 @@ namespace qtcnet_client private async void MainTabControl_OnStoreItemDoubleClicked(object? sender, EventArgs e) { - if(sender is MainTabControl _ctrl && _ctrl.SelectedStoreItem?.Tag is int _itemId) + if (sender is MainTabControl _ctrl && _ctrl.SelectedStoreItem?.Tag is int _itemId) { // get store item var _item = await _apiService.GetStoreItem(_itemId); - if(_item.Success && _item.Data != null) + if (_item.Success && _item.Data != null) { // create buy form StoreItemForm _itemForm = new(_apiService) @@ -696,7 +707,7 @@ namespace qtcnet_client private async void _itemForm_OnBuyClicked(object? sender, EventArgs e) { - if(sender is StoreItemForm _form) + if (sender is StoreItemForm _form) { // buy the item var _res = await _apiService.BuyStoreItem(_form.ItemId); @@ -796,11 +807,9 @@ namespace qtcnet_client Username = _user.Data.Username, Bio = _user.Data.Bio, Status = _user.Data.Status, + ProfileImage = await _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId) }; - // get profile image - _profile.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId); - _profile.OnClose += ProfileForm_OnClose; OpenProfileForms.Add(_profile); @@ -810,11 +819,11 @@ namespace qtcnet_client private void _gatewayService_OnRoomUserListReceived(object? sender, EventArgs e) { - if(e is RoomListEventArgs _args) + if (e is RoomListEventArgs _args) { // get the open chat room form var _chatRoom = OpenChatRoomForms.FirstOrDefault(e => e.RoomId == _args.Room.Id); - if(_chatRoom != null) + if (_chatRoom != null) { // the users to the list _chatRoom.AddUsersToRoomList(_args.UserList); @@ -828,7 +837,7 @@ namespace qtcnet_client { // get the open chat room form var _chatRoom = OpenChatRoomForms.FirstOrDefault(e => e.RoomId == _args.Room.Id); - if(_chatRoom != null) + if (_chatRoom != null) { // build message control MessageControl _msg = new() @@ -840,7 +849,7 @@ namespace qtcnet_client // add message _chatRoom.AddMessage(_msg); - if(_args.User.Id != "0") + if (_args.User.Id != "0") await _chatRoom.LoadProfileImage(_msg, _args.User); // play sound @@ -973,5 +982,28 @@ namespace qtcnet_client return default; } + + private void niMain_DoubleClick(object sender, EventArgs e) + { + if (WindowState == FormWindowState.Minimized) + { + Show(); + WindowState = FormWindowState.Normal; + } + } + + private void tsiShow_Click(object sender, EventArgs e) + { + if (WindowState == FormWindowState.Minimized) + { + Show(); + WindowState = FormWindowState.Normal; + } + } + + private void tsiExit_Click(object sender, EventArgs e) + { + Close(); + } } } diff --git a/qtcnet-client/Forms/MainForm.resx b/qtcnet-client/Forms/MainForm.resx index 8b2ff64..1fb4ee5 100644 --- a/qtcnet-client/Forms/MainForm.resx +++ b/qtcnet-client/Forms/MainForm.resx @@ -117,4 +117,87 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + + + 108, 17 + + + + + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAO24wAMtuMAFjbjABy24wAetuMAHHbjABW24wAL9uMAAzbjAAA24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAf24wAdNuMAMTbjADu24wA/duMAP/bjAD/24wA/9uMAPzbjADs24wAv9uM + AG3bjAAa24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAJ24wAYduMANXbjAD+24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/duMAM7bjABY24wABtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAA24wAEtuMAJPbjAD324wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPTbjACH24wADtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMABDbjACf24wA/duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPzbjACT24wAC9uMAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAE24wAh9uMAP3bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPrbjAB524wAAtuM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAE3bjADw24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AOrbjABA24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAQ24wAvduMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAK/bjAAK24wAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAFHbjAD324wA/9uM + AP/bjAD/24wA/9uLAP/biwD/24wA/9uMAP/bjAD/24wA/9uMAP/biwD/24wA/9uMAP/bjAD/24sA/9uL + AP/bjAD/24wA/9uMAP/bjAD/24wA8tuMAEPbjAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAC24wAntuM + AP/bjAD/24wA/9uLAP/ckQz/4Jwj/9+YG//bjQP/3JEM/9yPB//biwD/3ZIN/96YGv/bjQP/24wA/9uM + Af/elRX/4Jwk/92TD//biwD/24wA/9uMAP/bjAD/24wAj9uMAADbjAAAAAAAAAAAAAAAAAAA24wAANuM + ABbbjADU24wA/9uMAP/biwD/4qM1//Tet//57dj/+OnR/+/Ok//y16f/5atG/92TD//y2Kr/9N63/96V + FP/bjAL/6Lhi//fnzf/47Nf/9uPB/+WrR//biwD/24wA/9uMAP/bjADH24wAD9uMAAAAAAAAAAAAAAAA + AADbjAAA24wAMtuMAO7bjAD/24wA/92TD//14b3/89mt/+SoP//w0Jj///////Parv/dkg3/4qIy//rw + 3v/msFH/24wA/+OlOf/68N//7MJ5/+KkNf/uy47/+OrS/+CcJP/biwD/24wA/9uMAObbjAAm24wAAAAA + AAAAAAAAAAAAANuMAADbjABI24wA+duMAP/biwD/4qIy//nv3f/iozX/3pUX//LWpv/25cj/8tis/9uM + AP/ipDb/+ezY/+CcJ//aiQD/68F3//bjwv/ckAz/24oA/92RD//puWX/4Jwl/9uLAP/bjAD/24wA89uM + ADrbjAAAAAAAAAAAAAAAAAAA24wAANuMAFHbjAD824wA/9uKAP/jpzz/+e7b/+CdJ//bjAH/3ZMQ/+zD + fP/137v/240D/+KkNv/57Nj/4J0n/9qJAP/tx4X/89yz/9uNBP/bjAD/24wA/9qKAP/biwD/24wA/9uM + AP/bjAD324wAQtuMAAAAAAAAAAAAAAAAAADbjAAA24wATNuMAPrbjAD/24oA/+OnPP/57tv/4J0n/9uL + AP/aigD/7MJ6//Xfu//cjgX/5axI//rv3v/kqED/24sA/+3Hhf/z3LL/244E/9uMAP/bjAD/24sA/9uM + AP/bjAD/24wA/9uMAPXbjAA924wAAAAAAAAAAAAAAAAAANuMAADbjAA524wA8tuMAP/bigD/46Y6//nu + 2//gnin/24sA/9qKAP/sw37/9N+4/9yRC//x0p7//v37//Tdtv/dkxD/7cWB//Tdtv/cjgX/24wA/9uM + Av/elRb/3JAK/9uMAP/bjAD/24wA69uMACzbjAAAAAAAAAAAAAAAAAAA24wAANuMAB7bjADd24wA/9uL + AP/gmyL/+e3Z/+i4Yv/bjAD/3ZMP//TdtP/w0Jj/24sA/+WuS//68eD/5KpD/9uLAP/otl3/+e3Y/+Gf + Kv/biwD/46c8//XiwP/iozT/24sA/9uMAP/bjADS24wAFduMAAAAAAAAAAAAAAAAAADbjAAA24wABtuM + AK/bjAD/24wA/9uNAv/sxH3/+vDg//LZq//14sH/+OvU/+KkNv/aigD/4Z4p//HUov/fmB3/24oA/96V + Fv/03bX/+OnQ//LWpv/57dn/8NGa/9yQCv/bjAD/24wA/9uMAKDbjAAC24wAAAAAAAAAAAAAAAAAANuM + AADbjAAA24wAZtuMAP3bjAD/24wA/9yPCf/mr0//7cmI/+zCef/hoCz/24wA/9uMAP/bjQL/3I8I/9uN + Af/bjAD/24sA/96XGf/pu2r/7sqK/+i1XP/dkg//24sA/9uMAP/bjAD624wAVtuMAADbjAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAc24wA09uMAP/bjAD/24wA/9qKAP/biwD/2ooA/9uLAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24sA/9qKAP/biwD/2ooA/9uMAP/bjAD/24wA/9uMAMfbjAAU24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjABr24wA+9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD324wAXNuM + AADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAA7bjACr24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AJ7bjAAJ24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMACTbjADG24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAC724wAHduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuM + ACvbjADA24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD+24wAtduMACPbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADbjAAA24wAANuMABzbjACV24wA8duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA7tuMAIvbjAAW24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAAbbjABG24wAqtuMAOnbjAD+24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD924wA59uMAKTbjAA/24wABNuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjAAH24wALtuMAGXbjACS24wAq9uM + ALPbjACq24wAj9uMAGHbjAAq24wABduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuM + AADbjAAD24wABduMAALbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////AH///AAf//AAB//gAAP/wAAB/4AAAP+AAAD/AA + AAfwAAAH4AAAB+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD8AAAB/AAAAf4AAAP+AAAD/wA + AB/+AAA//wAAf/+AAP//4AP///4///////8= + + \ No newline at end of file