@@ -92,7 +92,15 @@ namespace winrt::YtFlowApp::implementation
9292 {
9393 model->AttachSubscriptionInfo (subscriptionInfo);
9494 }
95- m_model->ProxyGroups (single_threaded_observable_vector (std::move (proxyGroupModels)));
95+ auto observableProxyGroups = single_threaded_observable_vector (std::move (proxyGroupModels));
96+ observableProxyGroups.VectorChanged ([weak = lifetime->get_weak ()](auto const &, auto const &) {
97+ if (auto const self = weak.get ())
98+ {
99+ self->PopulateProxyGroupItemsForMenu ();
100+ }
101+ });
102+ m_model->ProxyGroups (std::move (observableProxyGroups));
103+ lifetime->PopulateProxyGroupItemsForMenu ();
96104 }
97105 catch (...)
98106 {
@@ -234,11 +242,12 @@ namespace winrt::YtFlowApp::implementation
234242 co_await resume_background ();
235243 auto conn = FfiDbInstance.Connect ();
236244 auto const newGroupId = conn.CreateProxyGroup (newGroupName.c_str (), " manual" );
237- auto const newGroupModel = make<ProxyGroupModel>( conn.GetProxyGroupById (newGroupId) );
245+ auto newGroup = conn.GetProxyGroupById (newGroupId);
238246 co_await resume_foreground (lifetime->Dispatcher ());
239247
248+ auto newGroupModel = make<ProxyGroupModel>(std::move (newGroup));
240249 m_model->ProxyGroups ().Append (newGroupModel);
241- RenameProxyGroupItem (newGroupModel);
250+ RenameProxyGroupItem (std::move ( newGroupModel) );
242251 }
243252 catch (...)
244253 {
@@ -429,6 +438,26 @@ namespace winrt::YtFlowApp::implementation
429438 Frame ().Navigate (xaml_typename<YtFlowApp::EditProxyPage>(), make<EditProxyPageParam>(isReadonly, proxyModel));
430439 }
431440
441+ void LibraryPage::PopulateProxyGroupItemsForMenu ()
442+ {
443+ ProxyGroupProxyDuplicateFlyout ().Items ().Clear ();
444+ auto const proxyGroups = m_model->ProxyGroups ();
445+ for (auto const proxyGroupModel : proxyGroups)
446+ {
447+ auto const proxyGroup = get_self<ProxyGroupModel>(proxyGroupModel);
448+ if (proxyGroup->IsSubscription ())
449+ {
450+ continue ;
451+ }
452+
453+ MenuFlyoutItem const menuItemForDuplicate;
454+ menuItemForDuplicate.Text (proxyGroup->Name ());
455+ menuItemForDuplicate.DataContext (proxyGroupModel);
456+ menuItemForDuplicate.Click ({get_weak (), &LibraryPage::ProxyGroupItemDuplicate_Click});
457+ ProxyGroupProxyDuplicateFlyout ().Items ().Append (menuItemForDuplicate);
458+ }
459+ }
460+
432461 void LibraryPage::ProxyGroupItem_Click (IInspectable const &sender, RoutedEventArgs const &)
433462 {
434463 auto const source = sender.as <FrameworkElement>();
@@ -641,8 +670,8 @@ namespace winrt::YtFlowApp::implementation
641670 }
642671 }
643672
644- fire_and_forget LibraryPage::ProxyGroupUnlockProxyButton_Click (Windows::Foundation::IInspectable const &sender,
645- Windows::UI::Xaml::RoutedEventArgs const &e)
673+ fire_and_forget LibraryPage::ProxyGroupUnlockButton_Click (Windows::Foundation::IInspectable const &sender,
674+ Windows::UI::Xaml::RoutedEventArgs const &e)
646675 {
647676 auto const lifetime = get_strong ();
648677 if (std::exchange (isDialogsShown, true ))
@@ -699,6 +728,76 @@ namespace winrt::YtFlowApp::implementation
699728 }
700729 EditProxyInCurrentProxyGroup (proxy);
701730 }
731+ fire_and_forget LibraryPage::ProxyGroupItemDuplicate_Click (Windows::Foundation::IInspectable const &sender,
732+ Windows::UI::Xaml::RoutedEventArgs const &)
733+ {
734+ try
735+ {
736+ auto const lifetime = get_strong ();
737+
738+ auto const targetGroup = sender.as <FrameworkElement>().DataContext ().try_as <ProxyGroupModel>();
739+ if (targetGroup == nullptr )
740+ {
741+ co_return ;
742+ }
743+ auto const targetGroupId = targetGroup->Id ();
744+ auto const allProxies = ProxyGroupProxyList ().Items ();
745+ using std::ranges::sort;
746+ using std::ranges::to;
747+ using std::ranges::views::filter;
748+ using std::ranges::views::transform;
749+ auto items = ProxyGroupProxyList ().SelectedItems () | to<std::vector>();
750+ sort (items, [&allProxies](auto const &lhs, auto const &rhs) {
751+ uint32_t lhsIndex{}, rhsIndex{};
752+ allProxies.IndexOf (lhs, lhsIndex);
753+ allProxies.IndexOf (rhs, rhsIndex);
754+ return lhsIndex < rhsIndex;
755+ });
756+ auto newProxies =
757+ items | transform ([](auto const &item) { return item.try_as <ProxyModel>(); }) |
758+ filter ([](auto const &item) { return static_cast <bool >(item); }) | transform ([](auto const &proxy) {
759+ return FfiDataProxy{
760+ .id = INVALID_DB_ID, .name = to_string (proxy->Name ()), .proxy = proxy->ProxyRaw ()};
761+ }) |
762+ to<std::vector>();
763+
764+ co_await resume_background ();
765+ auto conn = FfiDbInstance.Connect ();
766+ for (auto &proxy : newProxies)
767+ {
768+ try
769+ {
770+ proxy.id =
771+ conn.CreateProxy (targetGroupId, proxy.name .c_str (), proxy.proxy .data (), proxy.proxy .size (), 0 );
772+ // TODO: order_num
773+ }
774+ catch (...)
775+ {
776+ NotifyException (L" Duplicating a proxy" );
777+ }
778+ }
779+
780+ co_await resume_foreground (lifetime->Dispatcher ());
781+ size_t newProxyModelSize{};
782+ auto const targetGroupProxies = targetGroup->Proxies ();
783+ for (auto &&newProxyModel : newProxies | filter ([](auto const &proxy) {
784+ return proxy.id != INVALID_DB_ID;
785+ }) | transform ([](auto const &proxy) { return make<ProxyModel>(proxy); }))
786+ {
787+ if (targetGroupProxies)
788+ {
789+ targetGroupProxies.Append (std::move (newProxyModel));
790+ }
791+ newProxyModelSize++;
792+ }
793+ NotifyUser (L" Duplicated " + to_hstring (newProxyModelSize) + L" proxies to " + targetGroup->Name (),
794+ L" Duplicate Proxies" );
795+ }
796+ catch (...)
797+ {
798+ NotifyException (L" Duplicating proxies" );
799+ }
800+ }
702801 uint32_t LibraryPage::ProxyGroupProxySelectedCount ()
703802 {
704803 return ProxyGroupProxyList ().SelectedItems ().Size ();
0 commit comments