Initial themes implementation

This commit is contained in:
Dirk Alders 2020-01-26 21:01:31 +01:00
parent 03f0f73eb0
commit a24e772083
323 changed files with 2759 additions and 0 deletions

163
__init__.py Normal file
View File

@ -0,0 +1,163 @@
from django.conf import settings
from django.contrib.staticfiles.templatetags.staticfiles import static
from django.forms.models import model_to_dict
from django.utils.translation import gettext as _
import time
available_themes = [
('default', 'Default'),
('clear-red', 'Clear Red'),
('clear-green', 'Clear Green'),
('clear-blue', 'Clear Blue'),
]
default_theme = 'default'
class ThemeSettings(object):
def __init__(self):
from .models import Setting
s = Setting.objects.filter(id=1).first()
if s is None:
s = Setting(id=1)
s.save()
for attr_name in model_to_dict(s):
attr = getattr(s, attr_name)
if attr_name == 'page_theme' and attr == 'default':
setattr(self, attr_name, settings.DEFAULT_THEME)
else:
setattr(self, attr_name, attr)
class bar(list):
def __init__(self, turn_around=False):
self.time_measurement = time_measurement()
list.__init__(self)
self.turn_around = turn_around
self.debug = False
def index(self, entry_uid):
for i in range(0, len(self)):
if self[i].uid == entry_uid:
return i
raise ValueError('not in list')
def append_entry(self, *args, **kwargs):
self.append(entry(*args, **kwargs))
def replace_entry(self, entry_uid, *args, **kwargs):
i = self.index(entry_uid)
self[i] = entry(*args, **kwargs)
def append_entry_to_entry(self, entry_uid, *args, **kwargs):
i = self.index(entry_uid)
self[i].append(entry(*args, **kwargs))
@property
def entries(self):
rv = self[:]
if self.turn_around is True:
rv.reverse()
if self.debug is True:
rv.append(entry('time_measurement', self.time_measurement.time_str, None, None, True, False))
return rv
class Context(dict):
ACTIONBAR = 'actionbar'
BOTTOMBAR = 'bottombar'
MENUBAR = 'menubar'
NAVIGATIONBAR = 'navigationbar'
SETTINGS = 'settings'
TITLE = 'title'
def __init__(self, request):
from .models import BottomBar
#
dict.__init__(
self,
bottombar=bar(),
actionbar=bar(),
navigationbar=bar(turn_around=True),
menubar=bar(),
settings=ThemeSettings(),
title=ThemeSettings().page_title,
)
#
for i in range(1, 6):
for e in BottomBar.objects.filter(sequence_number=i):
if e.icon:
icon_url = e.icon.url
else:
icon_url = None
self[self.BOTTOMBAR].append(entry(
'bootombar-%d' % e.id,
e.name,
icon_url,
e.url,
e.left,
False
))
if settings.DEBUG:
self[self.BOTTOMBAR].debug = True
self[self.BOTTOMBAR].append(entry('bottombar-w3-validator', _('W3-Validator'), None, 'https://validator.w3.org/nu/?doc=' + request.build_absolute_uri(), False, False))
def set_additional_title(self, at):
if self[self.SETTINGS].page_title and at:
self[self.TITLE] = self[self.SETTINGS].page_title + ' - ' + at
else:
self[self.TITLE] = self[self.SETTINGS].page_title + at
class entry(list):
def __init__(self, uid, name, icon, url, left, active):
list.__init__(self)
self.uid = uid
self.name = name
self.icon = icon
self.url = url
self.left = left
self.active = active
@property
def is_dropdownmenu(self):
return len(self) > 0
def __str__(self):
return 'barentry: %s' % self.uid
def empty_entry_parameters(request):
return (
'empty', # uid
'', # name
transparency_icon_url(request), # icon
None, # url
True, # left
False # active
)
def get_themename(request):
return ThemeSettings().page_theme
class time_measurement(object):
def __init__(self):
self._start_time = time.time()
@property
def time_str(self):
return _('Time consumption') + ': %.2fs' % (time.time() - self._start_time)
def transparency_icon_url(request):
return static('themes/' + get_themename(request) + '/transparency.png')
def color_icon_url(request, icon_filename):
return static('themes/' + get_themename(request) + '/1st-color/%s' % icon_filename)
def gray_icon_url(request, icon_filename):
return static('themes/' + get_themename(request) + '/2nd-color/%s' % icon_filename)

5
admin.py Normal file
View File

@ -0,0 +1,5 @@
from django.contrib import admin
from .models import Setting, BottomBar
admin.site.register(Setting)
admin.site.register(BottomBar)

8
apps.py Normal file
View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
class ThemesConfig(AppConfig):
name = 'themes'
def ready(self):
import themes.signals

Binary file not shown.

View File

@ -0,0 +1,33 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-19 09:24+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: __init__.py:41
msgid "W3-Validator"
msgstr "W3-Validator"
#: __init__.py:107
msgid "Time consumption"
msgstr "Zeit"
#: templates/themes/clear-blue/base.html:23
#: templates/themes/clear-green/base.html:23
#: templates/themes/clear-red/base.html:23
msgid "Search..."
msgstr "Suche..."

View File

@ -0,0 +1,34 @@
# Generated by Django 2.2.5 on 2019-12-18 20:01
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='BottomBar',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=64)),
('icon', models.ImageField(blank=True, upload_to='theme')),
('url', models.URLField()),
('left', models.BooleanField()),
('sequence_number', models.SmallIntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')])),
],
),
migrations.CreateModel(
name='Setting',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('page_image', models.ImageField(default='theme/logo.png', upload_to='theme')),
('page_theme', models.CharField(choices=[('default', 'Default'), ('clear-red', 'Clear Red'), ('clear-green', 'Clear Green'), ('clear-blue', 'Clear Blue')], default='default', max_length=64)),
('page_title', models.CharField(blank=True, default='MyApp', max_length=32)),
],
),
]

0
migrations/__init__.py Normal file
View File

42
models.py Normal file
View File

@ -0,0 +1,42 @@
from django.db import models
from . import available_themes, default_theme
from PIL import Image
class Setting(models.Model):
page_image = models.ImageField(
upload_to='theme',
default='theme/logo.png'
)
page_theme = models.CharField(
max_length=64,
choices=available_themes,
default=default_theme
)
page_title = models.CharField(max_length=32, default='MyApp', blank=True)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.page_image.path)
if img.height > 50:
output_size = (int(img.width * 50 / img.height), 50)
img.thumbnail(output_size)
img.save(self.page_image.path)
class BottomBar(models.Model):
name = models.CharField(max_length=64, blank=True)
icon = models.ImageField(upload_to='theme', blank=True)
url = models.URLField()
left = models.BooleanField()
sequence_number = models.SmallIntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')])
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.icon:
img = Image.open(self.icon.path)
if img.height > 40:
output_size = (int(img.width * 40 / img.height), 40)
img.thumbnail(output_size)
img.save(self.icon.path)

74
signals.py Normal file
View File

@ -0,0 +1,74 @@
from django.db.models.signals import pre_delete, pre_save
from django.dispatch import receiver
from .models import BottomBar, Setting
import os
@receiver(pre_delete, sender=BottomBar)
def bottombar_auto_delete_file_on_delete(instance: BottomBar, **kwargs):
"""
Deletes file from filesystem
when corresponding `BottomBar` object is deleted.
"""
if instance.icon:
if os.path.isfile(instance.icon.path):
os.remove(instance.icon.path)
@receiver(pre_save, sender=BottomBar)
def bottombar_auto_delete_file_on_change(instance: BottomBar, **kwargs):
"""
Deletes old file from filesystem
when corresponding `icon` object is updated
with new file.
"""
if not instance.pk:
return False
try:
old_file = BottomBar.objects.get(pk=instance.pk).icon
except BottomBar.DoesNotExist:
return False
new_file = instance.icon
if not old_file == new_file:
if os.path.isfile(old_file.path):
os.remove(old_file.path)
@receiver(pre_delete, sender=Setting)
def setting_auto_delete_file_on_delete(instance: Setting, **kwargs):
"""
Deletes file from filesystem
when corresponding `Settings` object is deleted.
"""
if instance.page_image.path.endswith(instance.page_image.field.default):
return False
if instance.page_image:
if os.path.isfile(instance.page_image.path):
os.remove(instance.page_image.path)
@receiver(pre_save, sender=Setting)
def setting_auto_delete_file_on_change(instance: Setting, **kwargs):
"""
Deletes old file from filesystem
when corresponding `page_image` object is updated
with new file.
"""
if not instance.pk:
return False
try:
old_file = Setting.objects.get(pk=instance.pk).page_image
except Setting.DoesNotExist:
return False
if old_file.path.endswith(instance.page_image.field.default):
return False
new_file = instance.page_image
if not old_file == new_file:
if os.path.isfile(old_file.path):
os.remove(old_file.path)

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Some files were not shown because too many files have changed in this diff Show More