From 2efbd0801ecde7a7b7201d7e6a696c93c4f23273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vil=C3=A9m=20Duha?= Date: Thu, 11 Feb 2021 16:23:59 +0100 Subject: BlenderKit: several fixes for ratings UI Fast metadata - free full fix --- blenderkit/__init__.py | 2 +- blenderkit/ratings.py | 53 +++++++++++++++++++++++++++++++++-------------- blenderkit/ui_panels.py | 32 +++------------------------- blenderkit/upload.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++--- blenderkit/utils.py | 43 +++++++++++++++++++++++--------------- 5 files changed, 120 insertions(+), 65 deletions(-) diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index 3a0b9b0b..145e0fc8 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -574,7 +574,7 @@ class BlenderKitCommonSearchProps(object): def name_update(self, context): ''' checks for name change, because it decides if whole asset has to be re-uploaded. Name is stored in the blend file and that's the reason.''' - utils.name_update() + utils.name_update(self.blenderkit) diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py index c7e3d76b..320335e0 100644 --- a/blenderkit/ratings.py +++ b/blenderkit/ratings.py @@ -135,7 +135,7 @@ def update_ratings_work_hours(self, context): bkit_ratings = self url = paths.get_api_url() + f'assets/{self.asset_id}/rating/' - if bkit_ratings.rating_work_hours > 0.05: + if bkit_ratings.rating_work_hours > 0.45: ratings = [('working_hours', round(bkit_ratings.rating_work_hours, 1))] tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5, only_last=True) @@ -297,7 +297,7 @@ def update_ratings_work_hours_ui_1_5(self, context): class FastRateMenu(Operator): """Fast rating of the assets directly in the asset bar - without need to download assets.""" bl_idname = "wm.blenderkit_menu_rating_upload" - bl_label = "Send Rating" + bl_label = "Rate asset" bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} message: StringProperty( @@ -340,6 +340,8 @@ class FastRateMenu(Operator): min=0.0, max=300, update=update_ratings_work_hours ) + high_rating_warning = "This is a high rating, please be sure to give such rating only to amazing assets" + rating_work_hours_ui: EnumProperty(name="Work Hours", description="How many hours did this work take?", items=[('0', '0', ''), @@ -354,11 +356,12 @@ class FastRateMenu(Operator): ('10', '10', ''), ('15', '15', ''), ('20', '20', ''), - ('50', '50', ''), - ('100', '100', ''), - ('150', '150', ''), - ('200', '200', ''), - ('250', '250', ''), + ('30', '30', high_rating_warning), + ('50', '50', high_rating_warning), + ('100', '100', high_rating_warning), + ('150', '150', high_rating_warning), + ('200', '200', high_rating_warning), + ('250', '250', high_rating_warning), ], default='0', update=update_ratings_work_hours_ui ) @@ -391,14 +394,34 @@ class FastRateMenu(Operator): col.label(text=self.message) row = col.row() row.prop(self, 'rating_quality_ui', expand=True, icon_only=True, emboss=False) + # row.label(text=str(self.rating_quality)) col.separator() - col.prop(self, 'rating_work_hours') - if utils.profile_is_validator(): + + row = layout.row() + row.label(text=f"How many hours did this {self.asset_type} save you?") + + if self.asset_type in ('model', 'scene'): + row = layout.row() + if utils.profile_is_validator(): + col.prop(self, 'rating_work_hours') + row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True) + if int(self.rating_work_hours_ui) > 100: + utils.label_multiline(layout, + text=f"\nThat's huge! please be sure to give such rating only to godly {self.asset_type}s.\n", + width=500) + elif int(self.rating_work_hours_ui) > 18: + layout.separator() + + utils.label_multiline(layout, + text=f"\nThat's a lot! please be sure to give such rating only to amazing {self.asset_type}s.\n", + width=500) + + else: + + row = layout.row() - if self.asset_type == 'model': - row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True) - else: - row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True) + row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True) + def execute(self, context): user_preferences = bpy.context.preferences.addons['blenderkit'].preferences @@ -420,7 +443,7 @@ class FastRateMenu(Operator): rtgs = (('quality', self.rating_quality),) tasks_queue.add_task((send_rating_to_thread_quality, (url, rtgs, headers)), wait=2.5, only_last=True) - if self.rating_work_hours > 0.1: + if self.rating_work_hours > 0.45: rtgs = (('working_hours', round(self.rating_work_hours, 1)),) tasks_queue.add_task((send_rating_to_thread_work_hours, (url, rtgs, headers)), wait=2.5, only_last=True) return {'FINISHED'} @@ -437,7 +460,7 @@ class FastRateMenu(Operator): self.message = f"Rate asset {self.asset_name}" wm = context.window_manager - if utils.profile_is_validator() and self.asset_type == 'model': + if self.asset_type in ('model','scene'): # spawn a wider one for validators for the enum buttons return wm.invoke_props_dialog(self, width=500) else: diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index 302e7119..54cf1711 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -409,8 +409,8 @@ class VIEW3D_PT_blenderkit_model_properties(Panel): layout.label(text=str(ad['name'])) if o.instance_type == 'COLLECTION' and o.instance_collection is not None: layout.operator('object.blenderkit_bring_to_scene', text='Bring to scene') - layout.label(text='Ratings:') - draw_panel_model_rating(self, context) + # layout.label(text='Ratings:') + # draw_panel_model_rating(self, context) layout.label(text='Asset tools:') draw_asset_context_menu(self.layout, context, ad, from_panel=True) @@ -975,7 +975,7 @@ class VIEW3D_PT_blenderkit_unified(Panel): row.scale_y = 1.6 # split = row.split(factor=. col = layout.column() - col.prop(ui_props, 'asset_type', expand=True, icon_only=False) + col.prop(ui_props, 'asset_type', expand=True, icon_only=True) # row = layout.column(align = False) # layout.prop(ui_props, 'asset_type', expand=False, text='') @@ -1068,32 +1068,6 @@ class VIEW3D_PT_blenderkit_unified(Panel): else: layout.label(text='Switch to paint or sculpt mode.') - elif ui_props.down_up == 'RATING': # the poll functions didn't work here, don't know why. - - if ui_props.asset_type == 'MODEL': - # TODO improve poll here to parenting structures - if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.get( - 'asset_data') != None: - ad = bpy.context.active_object.get('asset_data') - layout.label(text=ad['name']) - draw_panel_model_rating(self, context) - if ui_props.asset_type == 'MATERIAL': - if bpy.context.view_layer.objects.active is not None and \ - bpy.context.active_object.active_material is not None and \ - bpy.context.active_object.active_material.blenderkit.asset_base_id != '': - layout.label(text=bpy.context.active_object.active_material.blenderkit.name + ' :') - # noinspection PyCallByClass - draw_panel_material_ratings(self, context) - if ui_props.asset_type == 'BRUSH': - if context.sculpt_object or context.image_paint_object: - props = utils.get_brush_props(context) - if props.asset_base_id != '': - layout.label(text=props.name + ' :') - # noinspection PyCallByClass - draw_panel_brush_ratings(self, context) - if ui_props.asset_type == 'TEXTURE': - layout.label(text='not yet implemented') - class BlenderKitWelcomeOperator(bpy.types.Operator): """Login online on BlenderKit webpage""" diff --git a/blenderkit/upload.py b/blenderkit/upload.py index 1901d92c..405c1100 100644 --- a/blenderkit/upload.py +++ b/blenderkit/upload.py @@ -536,6 +536,32 @@ def patch_individual_metadata(asset_id, metadata_dict, api_key): # op = layout.operator('wm.blenderkit_fast_metadata', text = ch['name']) +def update_free_full(self, context): + if self.asset_type == 'material': + if self.free_full == 'FULL': + self.free_full = 'FREE' + ui_panels.ui_message(title = "All BlenderKit materials are free", + message = "Any material uploaded to BlenderKit is free." \ + " However, it can still earn money for the author," \ + " based on our fair share system. " \ + "Part of subscription is sent to artists based on usage by paying users.") + +def can_edit_asset(active_index = -1, asset_data = None): + if active_index == -1 and not asset_data: + return False + profile = bpy.context.window_manager.get('bkit profile') + if profile is None: + return False + if utils.profile_is_validator(): + return True + if not asset_data: + sr = bpy.context.window_manager['search results'] + asset_data = dict(sr[active_index]) + # print(profile, asset_data) + if asset_data['author']['id'] == profile['user']['id']: + return True + return False + class FastMetadata(bpy.types.Operator): """Fast change of the category of object directly in asset bar.""" bl_idname = "wm.blenderkit_fast_metadata" @@ -594,11 +620,22 @@ class FastMetadata(bpy.types.Operator): default="PUBLIC", ) + free_full:EnumProperty( + name="Free or Full Plan", + items=( + ('FREE', 'Free', "You consent you want to release this asset as free for everyone"), + ('FULL', 'Full', 'Your asset will be in the full plan') + ), + description="Choose whether the asset should be free or in the Full Plan", + default="FULL", + update=update_free_full + ) + @classmethod def poll(cls, context): scene = bpy.context.scene ui_props = scene.blenderkitUI - return ui_props.active_index > -1 + return can_edit_asset(active_index=ui_props.active_index) def draw(self, context): layout = self.layout @@ -617,6 +654,7 @@ class FastMetadata(bpy.types.Operator): layout.prop(self, 'description') layout.prop(self, 'tags') layout.prop(self, 'is_private', expand=True) + layout.prop(self, 'free_full', expand=True) if self.is_private == 'PUBLIC': layout.prop(self, 'license') @@ -639,6 +677,7 @@ class FastMetadata(bpy.types.Operator): 'description': self.description, 'tags': comma2array(self.tags), 'isPrivate': self.is_private == 'PRIVATE', + 'isFree': self.free_full == 'FREE', 'license': self.license, } @@ -661,6 +700,8 @@ class FastMetadata(bpy.types.Operator): if result['id'] == self.asset_id: asset_data = dict(result) + if not can_edit_asset(asset_data=asset_data): + return {'CANCELLED'} self.asset_id = asset_data['id'] self.asset_type = asset_data['assetType'] cat_path = categories.get_category_path(bpy.context.window_manager['bkit_categories'], @@ -680,6 +721,11 @@ class FastMetadata(bpy.types.Operator): self.is_private = 'PRIVATE' else: self.is_private = 'PUBLIC' + + if asset_data['isFree']: + self.free_full = 'FREE' + else: + self.free_full = 'FULL' self.license = asset_data['license'] wm = context.window_manager @@ -994,9 +1040,10 @@ def start_upload(self, context, asset_type, reupload, upload_set): '''start upload process, by processing data, then start a thread that cares about the rest of the upload.''' # fix the name first - utils.name_update() - props = utils.get_upload_props() + + utils.name_update(props) + storage_quota_ok = check_storage_quota(props) if not storage_quota_ok: self.report({'ERROR_INVALID_INPUT'}, props.report) @@ -1215,6 +1262,8 @@ class AssetDebugPrint(Operator): if ad: result = ad.to_dict() if result: + t = bpy.data.texts.new(result['name']) + t.write(json.dumps(result, indent=4, sort_keys=True)) print(json.dumps(result, indent=4, sort_keys=True)) return {'FINISHED'} diff --git a/blenderkit/utils.py b/blenderkit/utils.py index 0892bdb2..26ace999 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -43,6 +43,7 @@ def experimental_enabled(): preferences = bpy.context.preferences.addons['blenderkit'].preferences return preferences.experimental_features + def get_process_flags(): flags = BELOW_NORMAL_PRIORITY_CLASS if sys.platform != 'win32': # TODO test this on windows @@ -215,7 +216,7 @@ def get_upload_props(): return s.blenderkit if ui_props.asset_type == 'HDR': - hdr = ui_props.hdr_upload_image#bpy.data.images.get(ui_props.hdr_upload_image) + hdr = ui_props.hdr_upload_image # bpy.data.images.get(ui_props.hdr_upload_image) if not hdr: return None return hdr.blenderkit @@ -254,7 +255,7 @@ def load_prefs(): fpath = paths.BLENDERKIT_SETTINGS_FILENAME if os.path.exists(fpath): try: - with open(fpath, 'r', encoding = 'utf-8') as s: + with open(fpath, 'r', encoding='utf-8') as s: prefs = json.load(s) user_preferences.api_key = prefs.get('API_key', '') user_preferences.global_dir = prefs.get('global_dir', paths.default_global_dict()) @@ -286,7 +287,7 @@ def save_prefs(self, context): fpath = paths.BLENDERKIT_SETTINGS_FILENAME if not os.path.exists(paths._presets): os.makedirs(paths._presets) - with open(fpath, 'w', encoding = 'utf-8') as s: + with open(fpath, 'w', encoding='utf-8') as s: json.dump(prefs, s, ensure_ascii=False, indent=4) except Exception as e: print(e) @@ -303,6 +304,7 @@ def uploadable_asset_poll(): return ui_props.hdr_upload_image is not None return True + def get_hidden_texture(img, force_reload=False): # i = get_hidden_image(tpath, bdata_name, force_reload=force_reload) # bdata_name = f".{bdata_name}" @@ -313,7 +315,8 @@ def get_hidden_texture(img, force_reload=False): t.image = img return t -def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace = 'sRGB'): + +def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace='sRGB'): if bdata_name[0] == '.': hidden_name = bdata_name else: @@ -339,13 +342,13 @@ def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace = 'sRGB') img.filepath = tpath img.reload() - image_utils.set_colorspace(img,colorspace) + image_utils.set_colorspace(img, colorspace) elif force_reload: if img.packed_file is not None: img.unpack(method='USE_ORIGINAL') img.reload() - image_utils.set_colorspace(img,colorspace) + image_utils.set_colorspace(img, colorspace) return img @@ -355,7 +358,7 @@ def get_thumbnail(name): img = bpy.data.images.get(name) if img == None: img = bpy.data.images.load(p) - image_utils.set_colorspace(img,'sRGB') + image_utils.set_colorspace(img, 'sRGB') img.name = name img.name = name @@ -378,16 +381,16 @@ def get_brush_props(context): return None -def p(text, text1='', text2='', text3='', text4='', text5='', level = 'DEBUG'): +def p(text, text1='', text2='', text3='', text4='', text5='', level='DEBUG'): '''debug printing depending on blender's debug value''' - if 1:#bpy.app.debug_value != 0: + if 1: # bpy.app.debug_value != 0: # print('-----BKit debug-----\n') # traceback.print_stack() - texts = [text1,text2,text3,text4,text5] + texts = [text1, text2, text3, text4, text5] text = str(text) for t in texts: - if t!= '': + if t != '': text += ' ' + str(t) bk_logger.debug(text) @@ -398,7 +401,7 @@ def copy_asset(fp1, fp2): '''synchronizes the asset between folders, including it's texture subdirectories''' if 1: bk_logger.debug('copy asset') - bk_logger.debug(fp1 +' '+ fp2) + bk_logger.debug(fp1 + ' ' + fp2) if not os.path.exists(fp2): shutil.copyfile(fp1, fp2) bk_logger.debug('copied') @@ -410,7 +413,7 @@ def copy_asset(fp1, fp2): target_subdir = os.path.join(target_dir, subdir.name) if os.path.exists(target_subdir): continue - bk_logger.debug(str(subdir) +' '+ str(target_subdir)) + bk_logger.debug(str(subdir) + ' ' + str(target_subdir)) shutil.copytree(subdir, target_subdir) bk_logger.debug('copied') @@ -638,11 +641,15 @@ def automap(target_object=None, target_slot=None, tex_size=1, bg_exception=False bpy.context.view_layer.objects.active = actob -def name_update(): +def name_update(props): + ''' + Update asset name function, gets run also before upload. Makes sure name doesn't change in case of reuploads, + and only displayName gets written to server. + ''' scene = bpy.context.scene ui_props = scene.blenderkitUI - props = get_upload_props() + # props = get_upload_props() if props.name_old != props.name: props.name_changed = True props.name_old = props.name @@ -674,7 +681,6 @@ def get_param(asset_data, parameter_name): return None - def params_to_dict(params): params_dict = {} for p in params: @@ -705,6 +711,7 @@ def dict_to_params(inputs, parameters=None): }) return parameters + def update_tags(self, context): props = self @@ -729,6 +736,7 @@ def update_tags(self, context): if props.tags != ns: props.tags = ns + def user_logged_in(): a = bpy.context.window_manager.get('bkit profile') if a is not None: @@ -826,5 +834,6 @@ def label_multiline(layout, text='', icon='NONE', width=-1): layout.label(text=l, icon=icon) icon = 'NONE' + def trace(): - traceback.print_stack() \ No newline at end of file + traceback.print_stack() -- cgit v1.2.3