Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVilem Duha <vilem.duha@gmail.com>2021-10-23 17:38:01 +0300
committerVilem Duha <vilem.duha@gmail.com>2021-10-24 20:11:15 +0300
commit490e63d2a5063c85ecb9eb14e35a98db7c96e5d3 (patch)
treed78d7242df343744c4dc4ff81ef35cf445b07c57 /blenderkit
parent996ff7f869357823867e3b02542418852e85aabd (diff)
BlenderKit: work on comments and notifications
Substantial progress on both, mainly layout and adaptation to new API. Comments now show threads and can be liked/disliked from addon Notifications now can open the related asset to see discussion.
Diffstat (limited to 'blenderkit')
-rw-r--r--blenderkit/__init__.py6
-rw-r--r--blenderkit/asset_bar_op.py2
-rw-r--r--blenderkit/comments_utils.py66
-rw-r--r--blenderkit/download.py2
-rw-r--r--blenderkit/search.py13
-rw-r--r--blenderkit/ui_panels.py114
-rw-r--r--blenderkit/utils.py17
7 files changed, 168 insertions, 52 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py
index 4a25c9d6..3b35b912 100644
--- a/blenderkit/__init__.py
+++ b/blenderkit/__init__.py
@@ -1730,12 +1730,18 @@ class BlenderKitAddonPreferences(AddonPreferences):
thumb_size: IntProperty(name="Assetbar thumbnail Size", default=96, min=-1, max=256)
+ #counts usages so it can encourage user after some time to do things.
asset_counter: IntProperty(name="Usage Counter",
description="Counts usages so it asks for registration only after reaching a limit",
default=0,
min=0,
max=20000)
+ notifications_counter: IntProperty(
+ name='Notifications Counter',
+ description='count users notifications',
+ default=0,
+ )
# this is now made obsolete by the new popup upon registration -ensures the user knows about the first search.
# first_run: BoolProperty(
# name="First run",
diff --git a/blenderkit/asset_bar_op.py b/blenderkit/asset_bar_op.py
index d13c3767..3403625c 100644
--- a/blenderkit/asset_bar_op.py
+++ b/blenderkit/asset_bar_op.py
@@ -788,7 +788,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
def search_more(self):
sro = bpy.context.window_manager.get('search results orig')
if sro is None:
- return;
+ return
if sro.get('next') is None:
return
search_props = utils.get_search_props()
diff --git a/blenderkit/comments_utils.py b/blenderkit/comments_utils.py
index cf6ccd06..23a17405 100644
--- a/blenderkit/comments_utils.py
+++ b/blenderkit/comments_utils.py
@@ -51,13 +51,13 @@ def upload_comment_thread(url, comment='', api_key=None):
# try:
r = rerequests.put(url, data=data, verify=True, headers=headers)
print(r)
- print(dir(r))
+ # print(dir(r))
print(r.text)
# except requests.exceptions.RequestException as e:
# print('ratings upload failed: %s' % str(e))
-def upload_comment_flag_thread(url, comment_id='', flag='like', api_key=None):
+def upload_comment_flag_thread( asset_id = '', comment_id='', flag='like', api_key=None):
''' Upload rating thread function / disconnected from blender data.'''
headers = utils.get_headers(api_key)
@@ -68,15 +68,21 @@ def upload_comment_flag_thread(url, comment_id='', flag='like', api_key=None):
"comment": comment_id,
"flag": flag,
}
+ url = paths.get_api_url() + 'comments/feedback/'
# try:
r = rerequests.post(url, data=data, verify=True, headers=headers)
- print(r)
- print(dir(r))
print(r.text)
- # except requests.exceptions.RequestException as e:
- # print('ratings upload failed: %s' % str(e))
+ #here it's important we read back, so likes are updated accordingly:
+ get_comments(asset_id, api_key)
+
+
+def send_comment_flag_to_thread(asset_id = '', comment_id='', flag='like', api_key = None):
+ '''Sens rating into thread rating, main purpose is for tasks_queue.
+ One function per property to avoid lost data due to stashing.'''
+ thread = threading.Thread(target=upload_comment_flag_thread, args=(asset_id, comment_id, flag, api_key))
+ thread.start()
def send_comment_to_thread(url, comment, api_key):
'''Sens rating into thread rating, main purpose is for tasks_queue.
@@ -100,6 +106,14 @@ def get_comments_local(asset_id):
return comments
return None
+def get_comments_thread(asset_id, api_key):
+ thread = threading.Thread(target=get_comments, args=([asset_id, api_key]), daemon=True)
+ thread.start()
+
+
+def get_comments_thread(asset_id, api_key):
+ thread = threading.Thread(target=get_comments, args=([asset_id, api_key]), daemon=True)
+ thread.start()
def get_comments(asset_id, api_key):
'''
@@ -120,11 +134,12 @@ def get_comments(asset_id, api_key):
r = rerequests.get(url, params=params, verify=True, headers=headers)
if r is None:
return
+ print(r.status_code)
if r.status_code == 200:
rj = r.json()
- comments = []
# store comments - send them to task queue
-
+ # print('retrieved comments')
+ # print(rj)
tasks_queue.add_task((store_comments_local, (asset_id, rj['results'])))
# if len(rj['results'])==0:
@@ -132,20 +147,21 @@ def get_comments(asset_id, api_key):
# tasks_queue.add_task((store_rating_local_empty,(asset_id,)))
# return ratings
+
+def store_notifications_count_local(all_count):
+ '''Store total count of notifications on server in preferences'''
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ user_preferences.notifications_counter = all_count
+
def store_notifications_local(notifications):
+ '''Store notifications in Blender'''
bpy.context.window_manager['bkit notifications'] = notifications
-def count_unread_notifications():
- notifications = bpy.context.window_manager.get('bkit notifications')
- if notifications is None:
- return 0
- unread = 0
- for n in notifications:
-
- if n['unread'] == 1:
- unread +=1
- print('counted', unread)
- return unread
+def count_all_notifications():
+ '''Return count of all notifications on server'''
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ return user_preferences.notifications_counter
+
def check_notifications_read():
'''checks if all notifications were already read, and removes them if so'''
@@ -158,14 +174,14 @@ def check_notifications_read():
bpy.context.window_manager['bkit notifications'] = None
return True
-def get_notifications(api_key, unread_count = 1000):
+def get_notifications(api_key, all_count = 1000):
'''
Retrieve notifications from BlenderKit server. Can be run from a thread.
Parameters
----------
api_key
- unread_count
+ all_count
Returns
-------
@@ -174,14 +190,16 @@ def get_notifications(api_key, unread_count = 1000):
params = {}
- url = paths.get_api_url() + 'notifications/api/unread_count/'
+ url = paths.get_api_url() + 'notifications/all_count/'
r = rerequests.get(url, params=params, verify=True, headers=headers)
if r.status_code ==200:
rj = r.json()
+ print(rj)
# no new notifications?
- if unread_count >= rj['unreadCount']:
+ if all_count >= rj['allCount']:
+ tasks_queue.add_task((store_notifications_count_local, ([rj['allCount']])))
+
return
- print('notifications', unread_count, rj['unreadCount'])
url = paths.get_api_url() + 'notifications/unread/'
r = rerequests.get(url, params=params, verify=True, headers=headers)
if r is None:
diff --git a/blenderkit/download.py b/blenderkit/download.py
index 9fb48073..f33e636f 100644
--- a/blenderkit/download.py
+++ b/blenderkit/download.py
@@ -1421,7 +1421,7 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
# if self.close_window:
# context.window.cursor_warp(event.mouse_x-1000, event.mouse_y - 1000);
- print(self.asset_base_id)
+ # print(self.asset_base_id)
wm = context.window_manager
# only make a pop up in case of switching resolutions
if self.invoke_resolution:
diff --git a/blenderkit/search.py b/blenderkit/search.py
index 0464f511..fc716fdc 100644
--- a/blenderkit/search.py
+++ b/blenderkit/search.py
@@ -108,8 +108,8 @@ def refresh_notifications_timer():
''' this timer gets notifications.'''
preferences = bpy.context.preferences.addons['blenderkit'].preferences
fetch_server_data()
- unread_notifications_count = comments_utils.count_unread_notifications()
- comments_utils.get_notifications(preferences.api_key, unread_count = unread_notifications_count)
+ all_notifications_count = comments_utils.count_all_notifications()
+ comments_utils.get_notifications(preferences.api_key, all_count = all_notifications_count)
return 300
@@ -730,7 +730,8 @@ def write_gravatar(a_id, gravatar_path):
adata['gravatarImg'] = gravatar_path
-def fetch_gravatar(adata):
+def fetch_gravatar(adata = None):
+
'''
Gets avatars from blenderkit server
Parameters
@@ -739,7 +740,7 @@ def fetch_gravatar(adata):
'''
# utils.p('fetch gravatar')
-
+ print(adata)
# fetch new avatars if available already
if adata.get('avatar128') is not None:
avatar_path = paths.get_temp_dir(subdir='bkit_g/') + adata['id'] + '.jpg'
@@ -784,7 +785,9 @@ fetching_gravatars = {}
def get_author(r):
- ''' Writes author info (now from search results) and fetches gravatar if needed.'''
+ ''' Writes author info (now from search results) and fetches gravatar if needed.
+ this is now tweaked to be able to get authors from
+ '''
global fetching_gravatars
a_id = str(r['author']['id'])
diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py
index add64653..d94d483d 100644
--- a/blenderkit/ui_panels.py
+++ b/blenderkit/ui_panels.py
@@ -593,7 +593,7 @@ class VIEW3D_PT_blenderkit_profile(Panel):
class MarkNotificationRead(bpy.types.Operator):
- """Visit subcategory"""
+ """Mark notification as read here and also on BlenderKit server"""
bl_idname = "wm.blenderkit_mark_notification_read"
bl_label = "Mark notification as read"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
@@ -620,17 +620,70 @@ class MarkNotificationRead(bpy.types.Operator):
return {'FINISHED'}
+class LikeComment(bpy.types.Operator):
+ """Mark notification as read here and also on BlenderKit server"""
+ bl_idname = "wm.blenderkit_like_comment"
+ bl_label = "BlenderKit like/dislike comment"
+ bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
+
+ asset_id: StringProperty(
+ name="Asset Base Id",
+ description="Unique id of the asset (hidden)",
+ default="",
+ options={'SKIP_SAVE'})
+
+ comment_id: bpy.props.IntProperty(
+ name="Id",
+ description="comment id",
+ default=-1)
+
+ flag: bpy.props.StringProperty(
+ name="flag",
+ description="Like/dislike comment",
+ default="like")
+
+ @classmethod
+ def poll(cls, context):
+ return True
+
+ def execute(self, context):
+
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ api_key = user_preferences.api_key
+ comments_utils.send_comment_flag_to_thread(asset_id = self.asset_id, comment_id=self.comment_id, flag=self.flag, api_key = api_key)
+ return {'FINISHED'}
+
+
def draw_notification(self, notification, width = 600):
layout = self.layout
box = layout.box()
-
- firstline = f"user {notification['actor']['id']} {notification['verb']}"
+ print(notification.to_dict())
+ firstline = f"{notification['actor']['string']} {notification['verb']} {notification['target']['string']}"
box1 = box.box()
row = box1.row()
utils.label_multiline(row, text=firstline, width = width)
- op = row.operator("wm.blenderkit_mark_notification_read", text="", icon='CHECKMARK')
+
+
+
+ op = row.operator("wm.blenderkit_mark_notification_read", text="", icon='CANCEL')
op.notification_id = notification['id']
- utils.label_multiline(box, text=notification['description'], width = width)
+ if notification['description']:
+ rows = utils.label_multiline(box, text=notification['description'], width = width)
+ split = rows[-1].split(factor = 0.8)
+
+ else:
+ row = layout.row()
+ split = row.split(factor = 0.8)
+ split.label(text = '')
+ split = split.split()
+ if notification['target']:
+ # row = layout.row()
+ # split = row.split(factor=.8)
+ # split.label(text='')
+ # split = split.split()
+ op = split.operator('wm.blenderkit_url', text='Open page', icon='GREASEPENCIL')
+ op.tooltip = 'Open the browser on the asset page to comment'
+ op.url = paths.get_bkit_url() + notification['target']['url']
def draw_notifications(self, context, width = 600):
layout = self.layout
@@ -1435,13 +1488,13 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
row = layout.row()
row.operator_context = 'INVOKE_DEFAULT'
- op = layout.operator('wm.blenderkit_fast_metadata', text='Edit Metadata')
+ op = layout.operator('wm.blenderkit_fast_metadata', text='Edit Metadata',icon='GREASEPENCIL')
op.asset_id = asset_data['id']
op.asset_type = asset_data['assetType']
if author_id == str(profile['user']['id']):
row.operator_context = 'EXEC_DEFAULT'
- op = layout.operator('wm.blenderkit_url', text='Edit Metadata (browser)')
+ op = layout.operator('wm.blenderkit_url', text='Edit Metadata (browser)', icon='GREASEPENCIL')
op.url = paths.get_bkit_url() + paths.BLENDERKIT_USER_ASSETS + f"/{asset_data['assetBaseId']}/?edit#"
row.operator_context = 'INVOKE_DEFAULT'
@@ -2036,7 +2089,13 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
op = name_row.operator('view3d.close_popup_button', text='', icon='CANCEL')
def draw_comment(self, context, layout, comment, width=330):
- box = layout.box()
+ row = layout.row()
+ # print(comment)
+ if comment['level']>0:
+ split = row.split(factor = 0.05 * comment['level'])
+ split.label(text='')
+ row = split.split()
+ box = row.box()
box.emboss = 'NORMAL'
row = box.row()
split = row.split(factor = 0.8)
@@ -2045,7 +2104,9 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
role_text = f" - moderator"
else:
role_text = ""
- split.label(text=f"{comment['submitDate']} - {comment['userName']}{role_text}")
+ row = split.row()
+ row.enabled = False
+ row.label(text=f"{comment['submitDate']} - {comment['userName']}{role_text}")
removal = False
likes = 0
dislikes = 0
@@ -2058,13 +2119,33 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
removal = True
# row = box.row()
split1 = split.split()
- split1.label(text=str(likes), icon='TRIA_UP')
- split1.label(text=str(dislikes), icon='TRIA_DOWN')
+ # split1.emboss = 'NONE'
+ op = split1.operator('wm.blenderkit_like_comment', text=str(likes), icon='TRIA_UP')
+ op.asset_id = self.asset_data['assetBaseId']
+ op.comment_id = comment['id']
+ op.flag = 'like'
+ op = split1.operator('wm.blenderkit_like_comment', text=str(dislikes), icon='TRIA_DOWN')
+ op.asset_id = self.asset_data['assetBaseId']
+ op.comment_id = comment['id']
+ op.flag = 'dislike'
+ # op = split1.operator('wm.blenderkit_like_comment', text='report', icon='ERROR')
+ # op.asset_id = self.asset_data['assetBaseId']
+ # op.comment_id = comment['id']
+ # op.flag = 'removal'
if removal:
+ row.alert = True
row.label(text='', icon='ERROR')
- utils.label_multiline(box, text=comment['comment'], width=width)
+ rows = utils.label_multiline(box, text=comment['comment'], width=width * (1 - 0.05 * comment['level']))
+
+ row = rows[-1]
+ split = row.split(factor=.8)
+ split.label(text='')
+ split = split.split()
+ op = split.operator('wm.blenderkit_url', text='Reply', icon='GREASEPENCIL')
+ op.tooltip = 'Open the browser on the asset page to comment'
+ op.url = paths.get_bkit_url() + f"/asset-gallery-detail/{self.asset_data['id']}/"
# box.label(text=str(comment['flags']))
def draw(self, context):
@@ -2094,9 +2175,11 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
tip_box.label(text=self.tip)
# comments
if utils.profile_is_validator() and bpy.app.debug_value == 2:
+ comments = bpy.context.window_manager.get('asset comments', {})
+ self.comments = comments.get(self.asset_data['assetBaseId'], [])
if self.comments is not None:
for comment in self.comments:
- self.draw_comment(context, layout, comment)
+ self.draw_comment(context, layout, comment, width = self.width)
def execute(self, context):
wm = context.window_manager
@@ -2132,8 +2215,8 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
api_key = user_preferences.api_key
comments = comments_utils.get_comments_local(asset_data['assetBaseId'])
- if comments is None:
- comments_utils.get_comments(asset_data['assetBaseId'], api_key)
+ # if comments is None:
+ comments_utils.get_comments_thread(asset_data['assetBaseId'], api_key)
comments = bpy.context.window_manager.get('asset comments', {})
self.comments = comments.get(asset_data['assetBaseId'], [])
@@ -2478,6 +2561,7 @@ classes = (
ClosePopupButton,
BlenderKitWelcomeOperator,
MarkNotificationRead,
+ LikeComment,
ShowNotifications,
)
diff --git a/blenderkit/utils.py b/blenderkit/utils.py
index d09c369b..5bbe96af 100644
--- a/blenderkit/utils.py
+++ b/blenderkit/utils.py
@@ -927,10 +927,11 @@ def label_multiline(layout, text='', icon='NONE', width=-1, max_lines=10):
Returns
-------
- True if max_lines was overstepped
+ rows of the text(to add extra elements)
'''
+ rows = []
if text.strip() == '':
- return
+ return [layout.row()]
text = text.replace('\r\n', '\n')
lines = text.split('\n')
if width > 0:
@@ -946,7 +947,9 @@ def label_multiline(layout, text='', icon='NONE', width=-1, max_lines=10):
if i < 1:
i = threshold
l1 = l[:i]
- layout.label(text=l1, icon=icon)
+ row = layout.row()
+ row.label(text=l1, icon=icon)
+ rows.append(row)
icon = 'NONE'
l = l[i:].lstrip()
li += 1
@@ -954,10 +957,12 @@ def label_multiline(layout, text='', icon='NONE', width=-1, max_lines=10):
break;
if li > max_lines:
break;
- layout.label(text=l, icon=icon)
+ row = layout.row()
+ row.label(text=l, icon=icon)
+ rows.append(row)
icon = 'NONE'
- if li > max_lines:
- return True
+ # if li > max_lines:
+ return rows
def trace():