diff --git a/CMakeLists.txt b/CMakeLists.txt
index ed437c0342b50..537d558c91c13 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,9 @@ endif()
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+set(NMC_RCC_FILE "nmctheme_v1.rcc")
+configure_file(${CMAKE_SOURCE_DIR}/${NMC_RCC_FILE} "${BIN_OUTPUT_DIRECTORY}/${NMC_RCC_FILE}" COPYONLY)
+
include(${CMAKE_SOURCE_DIR}/NEXTCLOUD.cmake)
set(QT_VERSION_MAJOR "6")
@@ -366,6 +369,7 @@ configure_file(version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
if(BUILD_OWNCLOUD_OSX_BUNDLE)
install(FILES sync-exclude.lst DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/)
configure_file(sync-exclude.lst bin/${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/sync-exclude.lst COPYONLY)
+ install(FILES nmctheme_v1.rcc DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/)
elseif(BUILD_CLIENT)
install( FILES sync-exclude.lst DESTINATION ${SYSCONFDIR}/${APPLICATION_SHORTNAME} )
configure_file(sync-exclude.lst bin/sync-exclude.lst COPYONLY)
diff --git a/cmake/modules/MacOSXBundleInfo.plist.in b/cmake/modules/MacOSXBundleInfo.plist.in
index a94e577d5d8fd..5d5960cbc65b9 100644
--- a/cmake/modules/MacOSXBundleInfo.plist.in
+++ b/cmake/modules/MacOSXBundleInfo.plist.in
@@ -35,13 +35,17 @@
CFBundleShortVersionString
@MIRALL_VERSION_STRING@
NSHumanReadableCopyright
- (C) 2014-2025 @APPLICATION_VENDOR_XML_ESCAPED@
+ (C) 2026 @APPLICATION_VENDOR_XML_ESCAPED@
NSSupportsAutomaticGraphicsSwitching
NSRequiresAquaSystemAppearance
SUShowReleaseNotes
+ SUEnableAutomaticChecks
+
+ SUAutomaticallyUpdate
+
SUPublicDSAKeyFile
dsa_pub.pem
SUPublicEDKey
diff --git a/nmctheme_v1.rcc b/nmctheme_v1.rcc
new file mode 100644
index 0000000000000..1e673f886e4f5
Binary files /dev/null and b/nmctheme_v1.rcc differ
diff --git a/shell_integration/MacOSX/CMakeLists.txt b/shell_integration/MacOSX/CMakeLists.txt
index 6da1e35c84dc1..8bcb614814fe3 100644
--- a/shell_integration/MacOSX/CMakeLists.txt
+++ b/shell_integration/MacOSX/CMakeLists.txt
@@ -2,7 +2,14 @@
# SPDX-FileCopyrightText: 2014 ownCloud GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
if(APPLE)
- set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/${APPLICATION_ICON_NAME}.icns")
+ # src/gui uses the branded application short name for the generated
+ # .icns file, while Nextcloud.cmake may still define APPLICATION_ICON_NAME
+ # as "Nextcloud".
+ if(NOT APPLICATION_NAME STREQUAL "Nextcloud")
+ set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/${APPLICATION_SHORTNAME}.icns")
+ else()
+ set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/${APPLICATION_ICON_NAME}.icns")
+ endif()
if (NEXTCLOUD_DEV)
set(XCODE_TARGET_CONFIGURATION "Debug")
diff --git a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m
index e5fd6bef26d96..7cf9a3255caeb 100644
--- a/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m
+++ b/shell_integration/MacOSX/NextcloudIntegration/FinderSyncExt/FinderSync.m
@@ -16,6 +16,10 @@ @interface FinderSync()
NSCondition *_menuIsComplete;
os_log_t _log;
}
+
+- (NSString *)socketPath;
+- (void)connectToSocketAtPath:(NSString *)socketPath;
+
@end
static os_log_t getFinderSyncLogger(void) {
@@ -35,20 +39,71 @@ - (NSString *)socketPath
{
NSBundle *extBundle = [NSBundle bundleForClass:[self class]];
NSString *groupIdentifier = [extBundle objectForInfoDictionaryKey:@"NCApplicationGroupIdentifier"];
+
if (!groupIdentifier.length) {
+ os_log_error(_log, "NCApplicationGroupIdentifier is missing.");
return nil;
}
+
NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:groupIdentifier];
+ if (!container) {
+ os_log_error(_log, "Could not resolve app group container for identifier: %{public}@", groupIdentifier);
+ return nil;
+ }
+
return [container URLByAppendingPathComponent:@"s" isDirectory:NO].path;
}
+- (void)connectToSocketAtPath:(NSString *)socketPath
+{
+ if (self.localSocketClient) {
+ return;
+ }
+
+ // FinderSync may start before the main application has created its socket.
+ if (![[NSFileManager defaultManager] fileExistsAtPath:socketPath]) {
+ os_log_debug(_log, "Socket does not exist yet, retrying: %{public}@", socketPath);
+
+ __weak typeof(self) weakSelf = self;
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ __strong typeof(self) self = weakSelf;
+ if (!self) {
+ return;
+ }
+
+ [self connectToSocketAtPath:socketPath];
+ });
+
+ return;
+ }
+
+ os_log_debug(_log, "Socket path determined and exists: %{public}@", socketPath);
+
+ self.lineProcessor = [[FinderSyncSocketLineProcessor alloc] initWithDelegate:self];
+ self.localSocketClient = [[LocalSocketClient alloc] initWithSocketPath:socketPath lineProcessor:self.lineProcessor];
+
+ __weak typeof(self) weakSelf = self;
+ self.localSocketClient.connectionEstablishedHandler = ^{
+ __strong typeof(self) self = weakSelf;
+ if (!self) {
+ return;
+ }
+
+ os_log_debug(self->_log, "Socket connection established.");
+ [self.localSocketClient askOnSocket:@"" query:@"GET_STRINGS"];
+ };
+
+ [self.localSocketClient start];
+}
+
- (instancetype)init
{
- self = [super init];
+ self = [super init];
if (self) {
_log = getFinderSyncLogger();
os_log_debug(_log, "Initializing...");
+
FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
NSBundle *extBundle = [NSBundle bundleForClass:[self class]];
@@ -74,22 +129,14 @@ - (instancetype)init
_menuIsComplete = [[NSCondition alloc] init];
NSString *socketPath = [self socketPath];
-
os_log_debug(_log, "Socket path: %{public}@", socketPath);
if (socketPath) {
- self.lineProcessor = [[FinderSyncSocketLineProcessor alloc] initWithDelegate:self];
- self.localSocketClient = [[LocalSocketClient alloc] initWithSocketPath:socketPath
- lineProcessor:self.lineProcessor];
- __weak typeof(self) weakSelf = self;
- self.localSocketClient.connectionEstablishedHandler = ^{
- __strong typeof(self) self = weakSelf;
- [self.localSocketClient askOnSocket:@"" query:@"GET_STRINGS"];
- };
- [self.localSocketClient start];
+ [self connectToSocketAtPath:socketPath];
} else {
os_log_error(_log, "No socket path available. Not initiating local socket client.");
}
+
os_log_debug(_log, "Initialization completed.");
}
@@ -100,173 +147,216 @@ - (instancetype)init
- (void)requestBadgeIdentifierForURL:(NSURL *)url
{
- os_log_debug(_log, "Requesting badge identifier for URL: %{public}@", url.path);
- BOOL isDir;
- if ([[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory: &isDir] == NO) {
- os_log_error(_log, "Could not determine file type of %{public}@", [url path]);
- isDir = NO;
- }
-
- NSString* normalizedPath = [[url path] decomposedStringWithCanonicalMapping];
- [self.localSocketClient askForIcon:normalizedPath isDirectory:isDir];
- os_log_debug(_log, "Badge identifier request completed for: %{public}@", normalizedPath);
+ os_log_debug(_log, "Requesting badge identifier for URL: %{public}@", url.path);
+
+ BOOL isDir;
+ if ([[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory:&isDir] == NO) {
+ os_log_error(_log, "Could not determine file type of %{public}@", [url path]);
+ isDir = NO;
+ }
+
+ NSString *normalizedPath = [[url path] decomposedStringWithCanonicalMapping];
+ [self.localSocketClient askForIcon:normalizedPath isDirectory:isDir];
+
+ os_log_debug(_log, "Badge identifier request completed for: %{public}@", normalizedPath);
}
#pragma mark - Menu and toolbar item support
-- (NSString*) selectedPathsSeparatedByRecordSeparator
+- (NSString *)selectedPathsSeparatedByRecordSeparator
{
- os_log_debug(_log, "Building selected paths string with record separators");
- FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
- NSMutableString *string = [[NSMutableString alloc] init];
- [syncController.selectedItemURLs enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
- if (string.length > 0) {
- [string appendString:@"\x1e"]; // record separator
- }
- NSString* normalizedPath = [[obj path] decomposedStringWithCanonicalMapping];
- [string appendString:normalizedPath];
- }];
- os_log_debug(_log, "Selected paths string built: %lu paths", (unsigned long)syncController.selectedItemURLs.count);
- return string;
+ os_log_debug(_log, "Building selected paths string with record separators");
+
+ FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
+ NSMutableString *string = [[NSMutableString alloc] init];
+
+ [syncController.selectedItemURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+ if (string.length > 0) {
+ [string appendString:@"\x1e"];
+ }
+
+ NSString *normalizedPath = [[obj path] decomposedStringWithCanonicalMapping];
+ [string appendString:normalizedPath];
+ }];
+
+ os_log_debug(_log, "Selected paths string built: %lu paths", (unsigned long)syncController.selectedItemURLs.count);
+ return string;
}
- (void)waitForMenuToArrive
{
os_log_debug(_log, "Waiting for menu to arrive");
+
[self->_menuIsComplete lock];
[self->_menuIsComplete wait];
[self->_menuIsComplete unlock];
+
os_log_debug(_log, "Menu arrival wait completed");
}
- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu
{
os_log_debug(_log, "Building menu for menu kind: %lu", (unsigned long)whichMenu);
- if(![self.localSocketClient isConnected]) {
+
+ if (![self.localSocketClient isConnected]) {
os_log_error(_log, "Local socket client not connected, cannot build menu");
return nil;
}
-
- FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
- NSMutableSet *rootPaths = [[NSMutableSet alloc] init];
- [syncController.directoryURLs enumerateObjectsUsingBlock: ^(id obj, BOOL *stop) {
- [rootPaths addObject:[obj path]];
- }];
-
- // The server doesn't support sharing a root directory so do not show the option in this case.
- // It is still possible to get a problematic sharing by selecting both the root and a child,
- // but this is so complicated to do and meaningless that it's not worth putting this check
- // also in shareMenuAction.
- __block BOOL onlyRootsSelected = YES;
- [syncController.selectedItemURLs enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
- if (![rootPaths member:[obj path]]) {
- onlyRootsSelected = NO;
- *stop = YES;
- }
- }];
- os_log_debug(_log, "Root directories check: onlyRootsSelected = %d", onlyRootsSelected);
-
- NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
- [self.localSocketClient askOnSocket:paths query:@"GET_MENU_ITEMS"];
-
- // Since the LocalSocketClient communicates asynchronously. wait here until the menu
- // is delivered by another thread
+
+ FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
+ NSMutableSet *rootPaths = [[NSMutableSet alloc] init];
+
+ [syncController.directoryURLs enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
+ [rootPaths addObject:[obj path]];
+ }];
+
+ // The server doesn't support sharing a root directory so do not show the option in this case.
+ // It is still possible to get a problematic sharing by selecting both the root and a child,
+ // but this is so complicated to do and meaningless that it's not worth putting this check
+ // also in shareMenuAction.
+ __block BOOL onlyRootsSelected = YES;
+
+ [syncController.selectedItemURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+ if (![rootPaths member:[obj path]]) {
+ onlyRootsSelected = NO;
+ *stop = YES;
+ }
+ }];
+
+ os_log_debug(_log, "Root directories check: onlyRootsSelected = %d", onlyRootsSelected);
+
+ NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
+ [self.localSocketClient askOnSocket:paths query:@"GET_MENU_ITEMS"];
+
+ // Since LocalSocketClient communicates asynchronously, wait until the menu
+ // is delivered by another thread.
[self waitForMenuToArrive];
- id contextMenuTitle = [_strings objectForKey:@"CONTEXT_MENU_TITLE"];
- if (contextMenuTitle && !onlyRootsSelected) {
- os_log_debug(_log, "Creating context menu with title: %{public}@", contextMenuTitle);
- NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
- NSMenu *subMenu = [[NSMenu alloc] initWithTitle:@""];
- NSMenuItem *subMenuItem = [menu addItemWithTitle:contextMenuTitle action:nil keyEquivalent:@""];
- subMenuItem.submenu = subMenu;
- subMenuItem.image = [[NSBundle mainBundle] imageForResource:@"app.icns"];
-
- // There is an annoying bug in macOS (at least 10.13.3), it does not use/copy over the representedObject of a menu item
- // So we have to use tag instead.
- int idx = 0;
- for (NSArray* item in _menuItems) {
- NSMenuItem *actionItem = [subMenu addItemWithTitle:[item valueForKey:@"text"]
- action:@selector(subMenuActionClicked:)
- keyEquivalent:@""];
- [actionItem setTag:idx];
- [actionItem setTarget:self];
- NSString *flags = [item valueForKey:@"flags"]; // e.g. "d"
- if ([flags rangeOfString:@"d"].location != NSNotFound) {
- [actionItem setEnabled:false];
- }
- idx++;
- }
- os_log_debug(_log, "Context menu created with %d items", idx);
- return menu;
- }
- os_log_debug(_log, "No context menu created: contextMenuTitle=%@, onlyRootsSelected=%d", contextMenuTitle != nil ? @"present" : @"absent", onlyRootsSelected);
- return nil;
+ id contextMenuTitle = [_strings objectForKey:@"CONTEXT_MENU_TITLE"];
+
+ if (contextMenuTitle && !onlyRootsSelected) {
+ os_log_debug(_log, "Creating context menu with title: %{public}@", contextMenuTitle);
+
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
+ NSMenu *subMenu = [[NSMenu alloc] initWithTitle:@""];
+ NSMenuItem *subMenuItem = [menu addItemWithTitle:contextMenuTitle action:nil keyEquivalent:@""];
+
+ subMenuItem.submenu = subMenu;
+ subMenuItem.image = [[NSBundle mainBundle] imageForResource:@"app.icns"];
+
+ // macOS does not reliably copy representedObject for Finder menu items,
+ // therefore use the tag as item index.
+ int idx = 0;
+
+ for (NSArray *item in _menuItems) {
+ NSMenuItem *actionItem = [subMenu addItemWithTitle:[item valueForKey:@"text"]
+ action:@selector(subMenuActionClicked:)
+ keyEquivalent:@""];
+
+ [actionItem setTag:idx];
+ [actionItem setTarget:self];
+
+ NSString *flags = [item valueForKey:@"flags"];
+ if ([flags rangeOfString:@"d"].location != NSNotFound) {
+ [actionItem setEnabled:false];
+ }
+
+ idx++;
+ }
+
+ os_log_debug(_log, "Context menu created with %d items", idx);
+ return menu;
+ }
+
+ os_log_debug(_log, "No context menu created: contextMenuTitle=%@, onlyRootsSelected=%d",
+ contextMenuTitle != nil ? @"present" : @"absent",
+ onlyRootsSelected);
+
+ return nil;
}
-- (void)subMenuActionClicked:(id)sender {
- long idx = [(NSMenuItem*)sender tag];
- os_log_debug(_log, "Menu item clicked at index: %ld", idx);
- NSString *command = [[_menuItems objectAtIndex:idx] valueForKey:@"command"];
- NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
- os_log_debug(_log, "Executing command: %{public}@", command);
- [self.localSocketClient askOnSocket:paths query:command];
- os_log_debug(_log, "Command execution completed");
+- (void)subMenuActionClicked:(id)sender
+{
+ long idx = [(NSMenuItem *)sender tag];
+
+ os_log_debug(_log, "Menu item clicked at index: %ld", idx);
+
+ NSString *command = [[_menuItems objectAtIndex:idx] valueForKey:@"command"];
+ NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
+
+ os_log_debug(_log, "Executing command: %{public}@", command);
+
+ [self.localSocketClient askOnSocket:paths query:command];
+
+ os_log_debug(_log, "Command execution completed");
}
#pragma mark - SyncClientProxyDelegate implementation
-- (void)setResult:(NSString *)result forPath:(NSString*)path
+- (void)setResult:(NSString *)result forPath:(NSString *)path
{
os_log_debug(_log, "Setting result: %{public}@ for path: %{public}@", result, path);
+
NSString *const normalizedPath = path.decomposedStringWithCanonicalMapping;
NSURL *const urlForPath = [NSURL fileURLWithPath:normalizedPath];
+
if (urlForPath == nil) {
os_log_error(_log, "Failed to create URL for path: %{public}@", normalizedPath);
return;
}
+
[FIFinderSyncController.defaultController setBadgeIdentifier:result forURL:urlForPath];
+
os_log_debug(_log, "Badge identifier set successfully");
}
-- (void)reFetchFileNameCacheForPath:(NSString*)path
+- (void)reFetchFileNameCacheForPath:(NSString *)path
{
os_log_debug(_log, "Refetching file name cache for path: %{public}@", path);
}
-- (void)registerPath:(NSString*)path
+- (void)registerPath:(NSString *)path
{
- os_log_debug(_log, "Registering path: %{public}@", path);
- NSAssert(_registeredDirectories, @"Registered directories should be a valid set!");
- [_registeredDirectories addObject:[NSURL fileURLWithPath:path]];
- [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
- os_log_debug(_log, "Path registration completed");
+ os_log_debug(_log, "Registering path: %{public}@", path);
+
+ NSAssert(_registeredDirectories, @"Registered directories should be a valid set!");
+
+ [_registeredDirectories addObject:[NSURL fileURLWithPath:path]];
+ [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
+
+ os_log_debug(_log, "Path registration completed");
}
-- (void)unregisterPath:(NSString*)path
+- (void)unregisterPath:(NSString *)path
{
- os_log_debug(_log, "Unregistering path: %{public}@", path);
- [_registeredDirectories removeObject:[NSURL fileURLWithPath:path]];
- [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
- os_log_debug(_log, "Path unregistration completed");
+ os_log_debug(_log, "Unregistering path: %{public}@", path);
+
+ [_registeredDirectories removeObject:[NSURL fileURLWithPath:path]];
+ [FIFinderSyncController defaultController].directoryURLs = _registeredDirectories;
+
+ os_log_debug(_log, "Path unregistration completed");
}
-- (void)setString:(NSString*)key value:(NSString*)value
+- (void)setString:(NSString *)key value:(NSString *)value
{
- os_log_debug(_log, "Setting string: %{public}@ = %{public}@", key, value);
- [_strings setObject:value forKey:key];
+ os_log_debug(_log, "Setting string: %{public}@ = %{public}@", key, value);
+ [_strings setObject:value forKey:key];
}
- (void)resetMenuItems
{
- os_log_debug(_log, "Resetting menu items");
- _menuItems = [[NSMutableArray alloc] init];
- os_log_debug(_log, "Menu items reset completed");
+ os_log_debug(_log, "Resetting menu items");
+ _menuItems = [[NSMutableArray alloc] init];
+ os_log_debug(_log, "Menu items reset completed");
}
-- (void)addMenuItem:(NSDictionary *)item {
+
+- (void)addMenuItem:(NSDictionary *)item
+{
os_log_debug(_log, "Adding menu item with title: %{public}@", [item valueForKey:@"text"] ?: @"(no title)");
- [_menuItems addObject:item];
- os_log_debug(_log, "Menu item added, total items: %lu", (unsigned long)_menuItems.count);
+
+ [_menuItems addObject:item];
+
+ os_log_debug(_log, "Menu item added, total items: %lu", (unsigned long)_menuItems.count);
}
- (void)menuHasCompleted
@@ -278,18 +368,22 @@ - (void)menuHasCompleted
- (void)connectionDidDie
{
- os_log_error(_log, "Connection to sync client died");
- [_strings removeAllObjects];
- [_registeredDirectories removeAllObjects];
- // For some reason the FIFinderSync cache doesn't seem to be cleared for the root item when
- // we reset the directoryURLs (seen on macOS 10.12 at least).
- // First setting it to the FS root and then setting it to nil seems to work around the issue.
- [FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:[NSURL fileURLWithPath:@"/"]];
- // This will tell Finder that this extension isn't attached to any directory
- // until we can reconnect to the sync client.
- [FIFinderSyncController defaultController].directoryURLs = nil;
- os_log_error(_log, "Connection cleanup completed, waiting for reconnection");
-}
+ os_log_error(_log, "Connection to sync client died");
-@end
+ [_strings removeAllObjects];
+ [_registeredDirectories removeAllObjects];
+
+ // For some reason the FIFinderSync cache doesn't seem to be cleared for the root item when
+ // we reset the directoryURLs (seen on macOS 10.12 at least).
+ // First setting it to the FS root and then setting it to nil seems to work around the issue.
+ [FIFinderSyncController defaultController].directoryURLs =
+ [NSSet setWithObject:[NSURL fileURLWithPath:@"/"]];
+
+ // This will tell Finder that this extension isn't attached to any directory
+ // until we can reconnect to the sync client.
+ [FIFinderSyncController defaultController].directoryURLs = nil;
+
+ os_log_error(_log, "Connection cleanup completed, waiting for reconnection");
+}
+@end
\ No newline at end of file
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Build.xcconfig b/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Build.xcconfig
index 2d11ace5ed34e..cfe490eb61326 100644
--- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Build.xcconfig
+++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudDev/Build.xcconfig
@@ -16,7 +16,7 @@ CURRENT_PROJECT_VERSION=$(CURRENT_PROJECT_VERSION:default=1)
//
// The development team identifier registered with Apple.
//
-DEVELOPMENT_TEAM=$(DEVELOPMENT_TEAM:default=NKUJUXUJ3B)
+DEVELOPMENT_TEAM=$(DEVELOPMENT_TEAM:default=S5724FNY84)
//
// The app name.
diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj
index c5739990c9e36..0a7c8f2b2fcee 100644
--- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj
+++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj
@@ -1400,7 +1400,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DEVELOPMENT_TEAM = NKUJUXUJ3B;
+ DEVELOPMENT_TEAM = S5724FNY84;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_TESTING_SEARCH_PATHS = YES;
@@ -1442,7 +1442,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DEVELOPMENT_TEAM = NKUJUXUJ3B;
+ DEVELOPMENT_TEAM = S5724FNY84;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTING_SEARCH_PATHS = YES;
GCC_NO_COMMON_BLOCKS = YES;
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 7f45acfeba5ed..6ce8887497080 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -20,9 +20,69 @@ if(APPLICATION_NAME STREQUAL "Nextcloud")
set(STATE_SUBDIR "nextcloud/")
endif()
-configure_file(${CMAKE_SOURCE_DIR}/theme.qrc.in ${CMAKE_SOURCE_DIR}/theme.qrc)
+# Remember the icon source name supplied by the Brander before replacing
+# it with the branded application name for generated resources.
+if(NOT DEFINED APPLICATION_ICON_NAME)
+ set(APPLICATION_ICON_NAME "${APPLICATION_SHORTNAME}")
+endif()
+
+set(APPLICATION_ICON_SOURCE_NAME "${APPLICATION_ICON_NAME}")
+
+if(NOT APPLICATION_NAME STREQUAL "Nextcloud")
+ set(APPLICATION_ICON_NAME "${APPLICATION_SHORTNAME}")
+endif()
+
+message(STATUS "APPLICATION_ICON_SOURCE_NAME: ${APPLICATION_ICON_SOURCE_NAME}")
+message(STATUS "APPLICATION_ICON_NAME: ${APPLICATION_ICON_NAME}")
+
set(theme_dir ${CMAKE_SOURCE_DIR}/theme)
+# The Brander still provides the customized source assets using the
+# Nextcloud filenames. Create branded aliases used by the build.
+if(NOT APPLICATION_ICON_SOURCE_NAME STREQUAL APPLICATION_ICON_NAME)
+
+ set(APP_ICON_SOURCE_SVG
+ "${theme_dir}/colored/${APPLICATION_ICON_SOURCE_NAME}-icon.svg")
+ set(APP_ICON_BRANDED_SVG
+ "${theme_dir}/colored/${APPLICATION_ICON_NAME}-icon.svg")
+
+ if(NOT EXISTS "${APP_ICON_SOURCE_SVG}")
+ message(FATAL_ERROR
+ "Application icon source does not exist: ${APP_ICON_SOURCE_SVG}")
+ endif()
+
+ configure_file(
+ "${APP_ICON_SOURCE_SVG}"
+ "${APP_ICON_BRANDED_SVG}"
+ COPYONLY
+ )
+
+ if(APPLE)
+ # Prefer the macOS-specific sidebar source.
+ set(MACOS_SIDEBAR_SOURCE_SVG
+ "${theme_dir}/colored/${APPLICATION_ICON_SOURCE_NAME}-macOS-sidebar.svg")
+
+ # Fallback for themes using the old generic sidebar filename.
+ if(NOT EXISTS "${MACOS_SIDEBAR_SOURCE_SVG}")
+ set(MACOS_SIDEBAR_SOURCE_SVG
+ "${theme_dir}/colored/${APPLICATION_ICON_SOURCE_NAME}-sidebar.svg")
+ endif()
+
+ if(NOT EXISTS "${MACOS_SIDEBAR_SOURCE_SVG}")
+ message(FATAL_ERROR
+ "macOS sidebar icon source does not exist: ${MACOS_SIDEBAR_SOURCE_SVG}")
+ endif()
+
+ configure_file(
+ "${MACOS_SIDEBAR_SOURCE_SVG}"
+ "${theme_dir}/colored/${APPLICATION_ICON_NAME}-sidebar.svg"
+ COPYONLY
+ )
+ endif()
+endif()
+
+configure_file(${CMAKE_SOURCE_DIR}/theme.qrc.in ${CMAKE_SOURCE_DIR}/theme.qrc)
+
set(client_UI_SRCS
accountsettings.ui
conflictdialog.ui
@@ -588,6 +648,7 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
install(FILES ${VISUAL_ELEMENTS} DESTINATION bin/visualelements)
install(FILES "${theme_dir}/${APPLICATION_EXECUTABLE}.VisualElementsManifest.xml" DESTINATION bin)
install(FILES ${client_I18N} DESTINATION i18n)
+ install(FILES ${CMAKE_SOURCE_DIR}/nmctheme_v1.rcc DESTINATION bin)
endif()
# we may not add MACOSX_BUNDLE here, if not building one
diff --git a/src/gui/application.cpp b/src/gui/application.cpp
index 0a3fa090bb88b..cb82d21008594 100644
--- a/src/gui/application.cpp
+++ b/src/gui/application.cpp
@@ -248,11 +248,12 @@ Application::Application(int &argc, char **argv)
// TODO: Can't set this without breaking current config paths
// setOrganizationName(QLatin1String(APPLICATION_VENDOR));
setOrganizationDomain(QLatin1String(APPLICATION_REV_DOMAIN));
-
setDesktopFileName(QString(LINUX_APPLICATION_ID));
-
setApplicationName(_theme->appName());
+
+#ifndef Q_OS_MACOS
setWindowIcon(_theme->applicationIcon());
+#endif
parseOptions(arguments());
//no need to waste time;
diff --git a/src/gui/main.cpp b/src/gui/main.cpp
index fe1089110940f..db9b63386e7fc 100644
--- a/src/gui/main.cpp
+++ b/src/gui/main.cpp
@@ -64,6 +64,17 @@ int main(int argc, char **argv)
qputenv("QML_IMPORT_PATH", (QDir::currentPath() + QStringLiteral("/qml")).toLatin1());
#endif
+ bool resourceLoaded = false;
+ const QString currentPath = QDir::currentPath();
+
+ if (Utility::isMac()) {
+ resourceLoaded = QResource::registerResource(QDir::toNativeSeparators("/Applications/MagentaCLOUD.app/Contents/Resources/nmctheme_v1.rcc"));
+ }
+
+ if (Utility::isWindows() || !resourceLoaded) {
+ resourceLoaded = QResource::registerResource(QDir::toNativeSeparators(currentPath + "/nmctheme_v1.rcc"));
+ }
+
Q_INIT_RESOURCE(resources);
Q_INIT_RESOURCE(theme);
diff --git a/theme.qrc.in b/theme.qrc.in
index 8ebb6e3d7b590..4336d90164fe6 100644
--- a/theme.qrc.in
+++ b/theme.qrc.in
@@ -146,6 +146,37 @@
+
+ theme/NMCIcons/accountAvatarIcon.svg
+ theme/NMCIcons/action-add.svg
+ theme/NMCIcons/cloud-security.svg
+ theme/NMCIcons/collapse-down.svg
+ theme/NMCIcons/collapse-right.svg
+ theme/NMCIcons/configuration1.png
+ theme/NMCIcons/configuration2.png
+ theme/NMCIcons/configuration3.png
+ theme/NMCIcons/logout.svg
+ theme/NMCIcons/navigation-left.svg
+ theme/NMCIcons/navigation-right.svg
+ theme/NMCIcons/pause.svg
+ theme/NMCIcons/remove.svg
+ theme/NMCIcons/website.svg
+
+
+ theme/NMCIcons/accountAvatarIcon-white.svg
+ theme/NMCIcons/logout-white.svg
+ theme/NMCIcons/pause-white.svg
+ theme/NMCIcons/remove-white.svg
+ theme/NMCIcons/website-white.svg
+ theme/close-white.svg
+ theme/more-white.svg
+ theme/settings-white.svg
+
+
+ theme/NMCIcons/ApplicationLogo.svg
+ theme/NMCIcons/folderLogo.svg
+ theme/NMCIcons/tlogocarrier.svg
+
theme/colored/wizard_logo.png
theme/colored/wizard_logo@2x.png
diff --git a/theme/NMCIcons/ApplicationLogo.svg b/theme/NMCIcons/ApplicationLogo.svg
new file mode 100644
index 0000000000000..efc8c94e1df28
--- /dev/null
+++ b/theme/NMCIcons/ApplicationLogo.svg
@@ -0,0 +1,16 @@
+
diff --git a/theme/NMCIcons/accountAvatarIcon-white.svg b/theme/NMCIcons/accountAvatarIcon-white.svg
new file mode 100644
index 0000000000000..1071c83ea6ef8
--- /dev/null
+++ b/theme/NMCIcons/accountAvatarIcon-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/accountAvatarIcon.svg b/theme/NMCIcons/accountAvatarIcon.svg
new file mode 100644
index 0000000000000..ba966999fc6cf
--- /dev/null
+++ b/theme/NMCIcons/accountAvatarIcon.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/theme/NMCIcons/action-add.svg b/theme/NMCIcons/action-add.svg
new file mode 100644
index 0000000000000..46df2f888cc15
--- /dev/null
+++ b/theme/NMCIcons/action-add.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/theme/NMCIcons/cloud-security.svg b/theme/NMCIcons/cloud-security.svg
new file mode 100644
index 0000000000000..bfa4b9cfc802a
--- /dev/null
+++ b/theme/NMCIcons/cloud-security.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/collapse-down.svg b/theme/NMCIcons/collapse-down.svg
new file mode 100644
index 0000000000000..b63406256c813
--- /dev/null
+++ b/theme/NMCIcons/collapse-down.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/collapse-right.svg b/theme/NMCIcons/collapse-right.svg
new file mode 100644
index 0000000000000..c353781f763c1
--- /dev/null
+++ b/theme/NMCIcons/collapse-right.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/configuration1.png b/theme/NMCIcons/configuration1.png
new file mode 100644
index 0000000000000..7a20bc1a11347
Binary files /dev/null and b/theme/NMCIcons/configuration1.png differ
diff --git a/theme/NMCIcons/configuration2.png b/theme/NMCIcons/configuration2.png
new file mode 100644
index 0000000000000..dbdac7d23fca2
Binary files /dev/null and b/theme/NMCIcons/configuration2.png differ
diff --git a/theme/NMCIcons/configuration3.png b/theme/NMCIcons/configuration3.png
new file mode 100644
index 0000000000000..66d2d513c8ad3
Binary files /dev/null and b/theme/NMCIcons/configuration3.png differ
diff --git a/theme/NMCIcons/folderLogo.svg b/theme/NMCIcons/folderLogo.svg
new file mode 100644
index 0000000000000..45f4cb770d6bb
--- /dev/null
+++ b/theme/NMCIcons/folderLogo.svg
@@ -0,0 +1,83 @@
+
+
+
+
diff --git a/theme/NMCIcons/logout-white.svg b/theme/NMCIcons/logout-white.svg
new file mode 100644
index 0000000000000..f449764e1a279
--- /dev/null
+++ b/theme/NMCIcons/logout-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/logout.svg b/theme/NMCIcons/logout.svg
new file mode 100644
index 0000000000000..babca11ccf863
--- /dev/null
+++ b/theme/NMCIcons/logout.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/navigation-left.svg b/theme/NMCIcons/navigation-left.svg
new file mode 100644
index 0000000000000..bfa5fa38304b4
--- /dev/null
+++ b/theme/NMCIcons/navigation-left.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/theme/NMCIcons/navigation-right.svg b/theme/NMCIcons/navigation-right.svg
new file mode 100644
index 0000000000000..a008c1d637d63
--- /dev/null
+++ b/theme/NMCIcons/navigation-right.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/theme/NMCIcons/pause-white.svg b/theme/NMCIcons/pause-white.svg
new file mode 100644
index 0000000000000..41fd92da98393
--- /dev/null
+++ b/theme/NMCIcons/pause-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/pause.svg b/theme/NMCIcons/pause.svg
new file mode 100644
index 0000000000000..7d8cc0999d9e9
--- /dev/null
+++ b/theme/NMCIcons/pause.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/remove-white.svg b/theme/NMCIcons/remove-white.svg
new file mode 100644
index 0000000000000..9a71790bcff30
--- /dev/null
+++ b/theme/NMCIcons/remove-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/remove.svg b/theme/NMCIcons/remove.svg
new file mode 100644
index 0000000000000..9896ad3ca78a7
--- /dev/null
+++ b/theme/NMCIcons/remove.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/tlogocarrier.svg b/theme/NMCIcons/tlogocarrier.svg
new file mode 100644
index 0000000000000..8fb2ff11a1050
--- /dev/null
+++ b/theme/NMCIcons/tlogocarrier.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/theme/NMCIcons/website-white.svg b/theme/NMCIcons/website-white.svg
new file mode 100644
index 0000000000000..4db891a1afe17
--- /dev/null
+++ b/theme/NMCIcons/website-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/NMCIcons/website.svg b/theme/NMCIcons/website.svg
new file mode 100644
index 0000000000000..4cdf4813f3dbe
--- /dev/null
+++ b/theme/NMCIcons/website.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/theme/close-white.svg b/theme/close-white.svg
new file mode 100644
index 0000000000000..f4f3c0c23cc5e
--- /dev/null
+++ b/theme/close-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/more-white.svg b/theme/more-white.svg
new file mode 100644
index 0000000000000..7efdfcbc6c514
--- /dev/null
+++ b/theme/more-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/theme/settings-white.svg b/theme/settings-white.svg
new file mode 100644
index 0000000000000..9004d38106663
--- /dev/null
+++ b/theme/settings-white.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file