Compare commits
4 Commits
version-1.
...
version-1.
Author | SHA1 | Date | |
---|---|---|---|
2bb859efd9 | |||
ac3943fe6c | |||
5eaee872bf | |||
6ce4399407 |
@@ -21,7 +21,7 @@
|
||||
bl_info = {
|
||||
'name': 'Blender Cloud Texture Browser',
|
||||
'author': 'Sybren A. Stüvel and Francesco Siddi',
|
||||
'version': (0, 2, 0),
|
||||
'version': (1, 0, 1),
|
||||
'blender': (2, 77, 0),
|
||||
'location': 'Ctrl+Shift+Alt+A anywhere',
|
||||
'description': 'Allows downloading of textures from the Blender Cloud. Requires '
|
||||
|
@@ -237,6 +237,7 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
self.loaded_images = set()
|
||||
self.check_credentials()
|
||||
|
||||
context.window.cursor_modal_set('DEFAULT')
|
||||
context.window_manager.modal_handler_add(self)
|
||||
self.timer = context.window_manager.event_timer_add(1 / 30, context.window)
|
||||
|
||||
@@ -268,24 +269,36 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
self.mouse_x = event.mouse_x
|
||||
self.mouse_y = event.mouse_y
|
||||
|
||||
if self._state == 'BROWSING' and event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
|
||||
left_mouse_release = event.type == 'LEFTMOUSE' and event.value == 'RELEASE'
|
||||
if self._state == 'PLEASE_SUBSCRIBE' and left_mouse_release:
|
||||
self.open_browser_subscribe()
|
||||
self._finish(context)
|
||||
return {'FINISHED'}
|
||||
|
||||
if self._state == 'BROWSING':
|
||||
selected = self.get_clicked()
|
||||
|
||||
if selected is None:
|
||||
# No item clicked, ignore it.
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
if selected.is_folder:
|
||||
self.descend_node(selected.node)
|
||||
if selected:
|
||||
context.window.cursor_set('HAND')
|
||||
else:
|
||||
if selected.file_desc is None:
|
||||
# This can happen when the thumbnail information isn't loaded yet.
|
||||
# Just ignore the click for now.
|
||||
# TODO: think of a way to handle this properly.
|
||||
return {'RUNNING_MODAL'}
|
||||
self.handle_item_selection(context, selected)
|
||||
context.window.cursor_set('DEFAULT')
|
||||
|
||||
elif event.type in {'RIGHTMOUSE', 'ESC'}:
|
||||
if left_mouse_release:
|
||||
if selected is None:
|
||||
# No item clicked, ignore it.
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
if selected.is_folder:
|
||||
self.descend_node(selected.node)
|
||||
else:
|
||||
if selected.file_desc is None:
|
||||
# This can happen when the thumbnail information isn't loaded yet.
|
||||
# Just ignore the click for now.
|
||||
# TODO: think of a way to handle this properly.
|
||||
return {'RUNNING_MODAL'}
|
||||
self.handle_item_selection(context, selected)
|
||||
|
||||
if event.type in {'RIGHTMOUSE', 'ESC'}:
|
||||
self._finish(context)
|
||||
return {'CANCELLED'}
|
||||
|
||||
@@ -301,6 +314,10 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
|
||||
try:
|
||||
await pillar.check_pillar_credentials()
|
||||
except pillar.NotSubscribedToCloudError:
|
||||
self.log.info('User not subscribed to Blender Cloud.')
|
||||
self._show_subscribe_screen()
|
||||
return
|
||||
except pillar.CredentialsNotSyncedError:
|
||||
self.log.info('Credentials not synced, re-syncing automatically.')
|
||||
else:
|
||||
@@ -310,6 +327,10 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
|
||||
try:
|
||||
await pillar.refresh_pillar_credentials()
|
||||
except pillar.NotSubscribedToCloudError:
|
||||
self.log.info('User is not a Blender Cloud subscriber.')
|
||||
self._show_subscribe_screen()
|
||||
return
|
||||
except pillar.UserNotLoggedInError:
|
||||
self.error('User not logged in on Blender ID.')
|
||||
else:
|
||||
@@ -320,6 +341,12 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
raise pillar.UserNotLoggedInError()
|
||||
# self._new_async_task(self._check_credentials())
|
||||
|
||||
def _show_subscribe_screen(self):
|
||||
"""Shows the "You need to subscribe" screen."""
|
||||
|
||||
self._state = 'PLEASE_SUBSCRIBE'
|
||||
bpy.context.window.cursor_set('HAND')
|
||||
|
||||
def descend_node(self, node):
|
||||
"""Descends the node hierarchy by visiting this node.
|
||||
|
||||
@@ -378,6 +405,7 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
|
||||
context.space_data.draw_handler_remove(self._draw_handle, 'WINDOW')
|
||||
context.window_manager.event_timer_remove(self.timer)
|
||||
context.window.cursor_modal_restore()
|
||||
|
||||
if self.maximized_area:
|
||||
bpy.ops.screen.screen_full_area(use_hide_panels=True)
|
||||
@@ -477,7 +505,7 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
self.log.debug('Browsing assets at project %r node %r', self.project_uuid, self.node_uuid)
|
||||
self._new_async_task(self.async_download_previews())
|
||||
|
||||
def _new_async_task(self, async_task: asyncio.coroutine, future: asyncio.Future=None):
|
||||
def _new_async_task(self, async_task: asyncio.coroutine, future: asyncio.Future = None):
|
||||
"""Stops the currently running async task, and starts another one."""
|
||||
|
||||
self.log.debug('Setting up a new task %r, so any existing task must be stopped', async_task)
|
||||
@@ -499,6 +527,7 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
'BROWSING': self._draw_browser,
|
||||
'DOWNLOADING_TEXTURE': self._draw_downloading,
|
||||
'EXCEPTION': self._draw_exception,
|
||||
'PLEASE_SUBSCRIBE': self._draw_subscribe,
|
||||
}
|
||||
|
||||
if self._state in drawers:
|
||||
@@ -641,6 +670,11 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
blf.draw(font_id, line)
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
def _draw_subscribe(self, context):
|
||||
self._draw_text_on_colour(context,
|
||||
'Click to subscribe to the Blender Cloud',
|
||||
(0.0, 0.0, 0.2, 0.6))
|
||||
|
||||
def get_clicked(self) -> MenuItem:
|
||||
|
||||
for item in self.current_display_content:
|
||||
@@ -689,6 +723,13 @@ class BlenderCloudBrowser(bpy.types.Operator):
|
||||
future=signalling_future))
|
||||
self.async_task.add_done_callback(texture_download_completed)
|
||||
|
||||
def open_browser_subscribe(self):
|
||||
import webbrowser
|
||||
|
||||
webbrowser.open_new_tab('https://cloud.blender.org/join')
|
||||
|
||||
self.report({'INFO'}, 'We just started a browser for you.')
|
||||
|
||||
|
||||
# store keymaps here to access after registration
|
||||
addon_keymaps = []
|
||||
|
@@ -31,14 +31,15 @@ class UserNotLoggedInError(RuntimeError):
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
return 'UserNotLoggedInError'
|
||||
return self.__class__.__name__
|
||||
|
||||
|
||||
class CredentialsNotSyncedError(UserNotLoggedInError):
|
||||
"""Raised when the user may be logged in on Blender ID, but has no Blender Cloud token."""
|
||||
|
||||
def __str__(self):
|
||||
return 'CredentialsNotSyncedError'
|
||||
|
||||
class NotSubscribedToCloudError(UserNotLoggedInError):
|
||||
"""Raised when the user may be logged in on Blender ID, but has no Blender Cloud token."""
|
||||
|
||||
|
||||
class PillarError(RuntimeError):
|
||||
@@ -171,11 +172,24 @@ async def check_pillar_credentials():
|
||||
if not subclient:
|
||||
raise CredentialsNotSyncedError()
|
||||
|
||||
pillar_user_id = subclient['subclient_user_id']
|
||||
if not pillar_user_id:
|
||||
raise CredentialsNotSyncedError()
|
||||
|
||||
try:
|
||||
await get_project_uuid('textures') # Any query will do.
|
||||
db_user = await pillar_call(pillarsdk.User.find, pillar_user_id)
|
||||
except pillarsdk.UnauthorizedAccess:
|
||||
raise CredentialsNotSyncedError()
|
||||
|
||||
roles = db_user.roles
|
||||
log.debug('User has roles %r', roles)
|
||||
if not roles or not {'subscriber', 'demo'}.intersection(set(roles)):
|
||||
# Delete the subclient info. This forces a re-check later, which can
|
||||
# then pick up on the user's new status.
|
||||
del profile.subclients[SUBCLIENT_ID]
|
||||
profile.save_json()
|
||||
raise NotSubscribedToCloudError()
|
||||
|
||||
|
||||
async def refresh_pillar_credentials():
|
||||
"""Refreshes the authentication token on Pillar.
|
||||
@@ -197,7 +211,7 @@ async def refresh_pillar_credentials():
|
||||
|
||||
# Test the new URL
|
||||
_pillar_api = None
|
||||
await get_project_uuid('textures') # Any query will do.
|
||||
await check_pillar_credentials()
|
||||
|
||||
|
||||
async def get_project_uuid(project_url: str) -> str:
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Primary requirements:
|
||||
CacheControl==0.11.6
|
||||
lockfile==0.12.2
|
||||
pillarsdk==1.0.0
|
||||
pillarsdk==1.1.2
|
||||
wheel==0.29.0
|
||||
|
||||
# Secondary requirements:
|
||||
|
2
setup.py
2
setup.py
@@ -173,7 +173,7 @@ setup(
|
||||
'wheels': BuildWheels},
|
||||
name='blender_cloud',
|
||||
description='The Blender Cloud addon allows browsing the Blender Cloud from Blender.',
|
||||
version='1.0.0',
|
||||
version='1.0.1',
|
||||
author='Sybren A. Stüvel',
|
||||
author_email='sybren@stuvel.eu',
|
||||
packages=find_packages('.'),
|
||||
|
Reference in New Issue
Block a user