Technical Documentation Aplikasi Jadwal Sholat Odoo 14 # Part 3

Bismillah,
Assalamu'alaikum Warohmatullah Wabarokatuh,


Setelah 1 tahun yang lalu saya posting blog terkait technical documentation aplikasi jadwal sholat yang belum 100% selesai, pada kesempatan kali ini insyaAllah akan saya lanjutkan technical documentation part 3 yang isinya untuk mempercantik tampilan dan penambahan fitur - fitur dari display jadwal sholatnya.

1. Membuat field konfigurasi untuk mengubah tampilan display

Agar tema displaynya bisa kita ubah sewaktu - waktu di konfigurasi, bisa kita tambahkan field selection, dan jika ada design tema display baru bisa kita tambahkan value selectionnya dari codingan

di dalam file models/model.py  di object res.company tambahkan field display_theme :

class ResCompany(models.Model):
_inherit = 'res.company'

    ....
    display_theme = fields.Selection([('jadwal_sholat_view', 'Tema 1'), ('jadwal_sholat_2', 'Tema 2')], string="Tema Display", default='jadwal_sholat_view')

Tampilkan field display_theme di form view object res.company :

<!-- INHERIT FORM COMPANY -->

<record id="view_company_jaska_inherit" model="ir.ui.view">
<field name="name">res.company.jaska.inherit</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<field name="favicon" position="after">
<field name="display_theme" required="1"/>
                 ....
</field>

</field>
</record>

<!-- ========================== -->



2. Buat file css untuk mempercantik tampilan display dan buat file xml baru untuk tampilan display dan buat id templatenya sesuai value selection dari field display theme

Untuk css utamanya saya menggunakan file "bootstrap.min.css" dalam direktori static/src/css, filenya bisa download disini.

Kemudian untuk css yang kedua saya namakan file css "main_screen_2.css", dan tempatkan di static/src/css dengan isi sebagai berikut :

.text-box {
text-shadow: 2px 4px 3px rgba(0,0,0,0.3);
color:white;
height:100px;
width:700px;
text-align: center;
padding:15px;
font-size: 20px;
margin-left:10px;
padding-top: 27px;
font-weight:normal;
display:inline-block;
padding-top: 0px;
}


.running-text {
font-family: 'PT Sans Regular';
display: block;
font-size: 15pt;
position: relative;
height: 45px;
}
.running-text div {
padding: 12px 1rem 1rem 1rem;
float: left;
}

.header {
background-color: #47a522;
height: 90px;
box-shadow: 5px 3px 25px;
overflow: hidden;
width: 100%;
opacity: 0.8;
text-align: center;
z-index:-1;
position:absolute;
padding-bottom: 0px;
height:100px
}
.header span {
padding-top: 12px;
padding-bottom: 12px;
text-align: center;
font-size:30;
color:white;
text-shadow: 2px 4px 3px rgba(0,0,0,0.3);
font-weight:bold;
}
.footer {
background-color: #867584;
height: 50px;
box-shadow: 5px 3px 25px;
font-size: 22pt;
overflow: hidden;
width: 100%;
color:white;
text-shadow: 2px 4px 3px rgba(0,0,0,0.3);
bottom: 0px;
position: fixed;
opacity:80%;
/* margin; */
background-color:black;
}
.background {
width: 100%;
background-color: gray;
}
.background img {
min-width: 100%;
min-height: 100%;
max-height: 100%;
max-width: 100%;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: -1;
}

.jadwal-sholat {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 15%;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19) ;
text-shadow: 2px 4px 3px rgba(0,0,0,0.3);
font-size:30;
opacity:0.8;
font-weight:bold;
position: fixed;
font-size:40;
bottom:50px;
}

.jadwal-sholat td, .jadwal-sholat th {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}

.jadwal-sholat tr:nth-child(even){background-color: #f2f2f2;}

.jadwal-sholat tr:hover {background-color: #ddd;}

.jadwal-sholat th {
padding-top: 12px;
padding-bottom: 12px;
text-align: center;
background-color: #47a522;
color: white;
}


Untuk file xml-nya saya namakan "jadwal_sholat_2.xml" dan tempatkan di static/src/xml, di tag header panggil 2 file css yang kita buat, berikut isi source codenya :

<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<template id="jadwal_sholat_2" name="Jadwal Sholat 2">
<head>
<link rel="stylesheet" href="/ab_jadwal_sholat/static/src/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/ab_jadwal_sholat/static/src/css/main_screen_2.css"/>

            <t t-call-assets="web.assets_common" t-js="false"/>
<t t-call-assets="web.assets_common" t-css="false"/>
</head>
<body>
<div style="overflow: hidden;">
</div>
            <div class="background">
<t t-foreach="company.background_line" t-as="bg">
<t t-if="not bg.bg_iqomah and not bg.bg_before_adzan">
<img t-att-src="'data:image/png;base64,%s' % to_text(bg.background)" t-att-class="'bg%s' % to_text(bg.id)" t-att-id="'bg%s' % to_text(bg.id)" style="
min-width: 70%;
min-height: 100%;
max-height: 100%;
max-width: 70%;
margin: auto;
margin-top: 5.5%;
position: fixed;
padding-bottom: 12%;
top: 2%;
left: 1%;
bottom: 0;
right: 30%;
"/>

</t>
</t>
</div>

<div class="header">
<span t-esc="company.name"/>
<br/>
<span class="address text-box" style="font-size:20px; font-weight:normal; width:700px;display:inline-block;padding-top: 0px;"/>
</div>

<table class="jadwal-sholat" style="bottom:75.3%; left:72%; width: 26.5%;font-size:40px">
<tr >
<td class="tanggal">
<div class="tanggal">
<span class="day">Loading...</span>
</div>
<div class="tanggal">
<span class="date">Loading...</span>
</div>
</td>
</tr>
</table>

<table class="jadwal-sholat" style="bottom:65%; left:72%; width: 26.5%;font-size:70px">
<tr >
<td class="time">
<span class="hour">00</span>: <span class="minute">00</span>: <span class="second">00</span>
</td>
</tr>
</table>



<table class="jadwal-sholat" style="bottom:51.5%; left:72%; width: 12.5%;">
<tr >
<th style="padding:0px" class="subuh">Subuh</th>
</tr>
<tr>
<td class="subuh-text" style="font-size:60px;padding:0px"/>
</tr>
</table>

<table class="jadwal-sholat" style="bottom:38%; left:72%; width: 12.5%;">
<tr >
<th style="padding:0px" class="terbit">Syuruq</th>
</tr>
<tr>
<td class="sunrise-text" style="font-size:60px;padding:0px"/>
</tr>
</table>

<table class="jadwal-sholat" style="bottom:24.5%; left:72%; width: 12.5%;">
<tr >
<th style="padding:0px" class="dhuha">Dhuha</th>
</tr>
<tr>
<td class="dhuha-text" style="font-size:60px;padding:0px"/>
</tr>
</table>

<table class="jadwal-sholat" style="bottom:11%; left:72%; width: 12.5%;">
<tr >
<th style="padding:0px" class="dzuhur-jumat"></th>
</tr>
<tr>
<td class="duhur-text" style="font-size:60px;padding:0px"/>
</tr>
</table>

<table class="jadwal-sholat" style="bottom:51.5%; left:86%; width: 12.5%;">
<tr >
<th style="padding:0px" class="ashar">Ashar</th>
</tr>
<tr>
<td class="ashar-text" style="font-size:60px;padding:0px"/>
</tr>
</table>

<table class="jadwal-sholat" style="bottom:38%; left:86%; width: 12.5%;">
<tr >
<th style="padding:0px" class="maghrib">Maghrib</th>
</tr>
<tr>
<td class="maghrib-text" style="font-size:60px;padding:0px"/>
</tr>
</table>

<table class="jadwal-sholat" style="bottom:24.5%; left:86%; width: 12.5%;">
<tr >
<th style="padding:0px" class="isya">Isya</th>
</tr>
<tr>
<td class="isya-text" style="font-size:60px;padding:0px"/>
</tr>
</table>

<div class="footer" style="height: 9%">
<div class="running-text">
<marquee behavior="scroll" direction="left" scrollamount="20">
<span class="info-text" style="font-size:60px; opacity: 100%;color:white;font-weight:bold;">Loading...</span>
</marquee>
</div>
</div>

<span id="company" t-esc="company.id" style="display: none;"/>

</body>
</template>
</odoo>


Jangan lupa untuk panggil file xml-nya di file __manifest__.py

{
...
# always loaded
'data': [
         ...
'static/src/xml/jadwal_sholat_2.xml',
        ...
    ],
...
}

3. Update file static/src/jadwal_sholat.js untuk menambahkan logic fitur - fiturnya, diantaranya adalah :
    - Fitur untuk menampilkan alamat masjid atau hanya namanya saja (function SetAttributes dan displayAddress)
    - Fitur untuk mengganti gambar background display secara berkala sesuai waktu yang disetting di konfigurasi (function changeBackground)
    - Fitur untuk mengatur base color dari display, bisa statis dan bisa dinamis dari avarage RGB dari gambar background (function SetBaseColor dan getAverageRGB)

$().ready(function () {
....
rpc.query({
model: "res.company",
method: "get_settings",
args: [false, company],
}).then(function (data) {
settings = data;
var jadwal_sholat = SetPrayerTimes(settings);

            SetAttributes(settings);
displayAddress(settings);
changeBackground(settings);
SetBaseColor(settings, false);
});

        function SetAttributes(settings){
if (Object.keys(settings).length > 0){
                if (settings['company']['show_address'] === false){
$('.header span').css("font-size", '70');
}
};
}

        function displayAddress(settings){
if (Object.keys(settings).length > 1){
var street = settings['company']['street'] === false ? '' : settings['company']['street']
var street2 = settings['company']['street2'] === false ? '' : settings['company']['street2']
var city = settings['company']['city'] === false ? '' : settings['company']['city']
var state = settings['state']
var country = settings['country']
var phone = settings['company']['phone']
var address = `${street} ${street2} ${city} ${state} ${country} Telp. ${phone}`
var info = settings['info']
$('.address').html(address);
$('.info-text').html(info);
}
};
        
        function getAverageRGB(imgEl) {
var blockSize = 5, // only visit every 5 pixels
defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
canvas = document.createElement('canvas'),
context = canvas.getContext && canvas.getContext('2d'),
data, width, height,
i = -4,
length,
rgb = {r:0,g:0,b:0},
count = 0;
if (!context) {
return defaultRGB;
}
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch(e) {
/* security error, img on diff domain */alert('x');
return defaultRGB;
}
length = data.data.length;
while ( (i += blockSize * 4) < length ) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i+1];
rgb.b += data.data[i+2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r/count);
rgb.g = ~~(rgb.g/count);
rgb.b = ~~(rgb.b/count);
return rgb;
}

        function changeBackground(settings){
if (Object.keys(settings).length > 1){
var images = settings['background'].filter(bg => bg.bg_iqomah === false && bg.bg_before_adzan === false)
var i = images.length;
var fadeout = true
var cross = 0
var interval = settings['company']['background_timer'] === 0 ? 10000 : settings['company']['background_timer'] * 60000
setInterval(() => {
if (fadeout)
{
--i;
if (i == 0){
fadeout = false;
}
}
else
{
++i;
if (i == images.length){
fadeout = true;
}
};
if (fadeout){
if (images[i]){
$(".bg" + images[i]['id']).fadeOut("slow");
var img = document.getElementById("bg" + images[i-1]['id'])
var rgb = getAverageRGB(img)
if (settings['company']['auto_sync_color']){
SetBaseColor(settings, rgb);
}
}
} else {
if (images[i]){
$(".bg" + images[i]['id']).fadeIn("slow");
var img = document.getElementById("bg" + images[i]['id'])
var rgb = getAverageRGB(img)
if (settings['company']['auto_sync_color']){
SetBaseColor(settings, rgb);
}
}
}
}, interval);
};
};


        function SetBaseColor(settings, rgb){
if (rgb){
$('.header').css("background-color", 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')' );
$('.jadwal-sholat th').css("background-color", 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')' );
} else {
if (Object.keys(settings).length > 0){
var last_image = settings['background'].length === 0 ? false : settings['background'][settings['background'].filter(bg => bg.bg_iqomah === false && bg.bg_before_adzan === false).length-1]['id']
var img = document.getElementById("bg" + last_image)
if (img){
var rgb = getAverageRGB(img);
}
if (settings['company']['auto_sync_color'] === false){
$('.header').css("background-color", settings['company']['base_color'] );
$('.jadwal-sholat th').css("background-color", settings['company']['base_color'] );
} else {
$('.header').css("background-color", 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')' );
$('.jadwal-sholat th').css("background-color", 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')' );
}
};
}
}
    });





4. Update file controller di controllers/controllers.py untuk merender view display yang sudah kita buat

# -*- coding: utf-8 -*-

from odoo import http
from odoo.http import request
from odoo.tools.translate import _


class jadwal_sholat_screen(http.Controller):
@http.route(['/jadwal_sholat'], type='http', methods=['POST', 'GET'], auth="public", website=True)
def jadwal_sholat(self, **kw):
com = request.env.user.company_id
img_src = '/website/image/res.company/%s/logo' % com.id

render_view = 'ab_jadwal_sholat.jadwal_sholat_view'
if com.display_theme:
render_view = 'ab_jadwal_sholat.%s' % com.display_theme
return request.render(render_view, {'image': img_src, 'company': com})

5. Terakhir untuk menjalankan fitur ganti background secara berkala kita perlu tambahkan lemparan dari database untuk list gambar di konfigurasi dan fitur running text di bawah dispay dengan mengupdate function get_settings di object res.company

def get_settings(self, company_id):
result = {}
if company_id:
company_id = int(company_id)
company = self.browse(company_id)
# Running Text Footer
quran = [] if not company.information_line else company.information_line.filtered(lambda x: x.type == 'quran').read()
hadits = [] if not company.information_line else company.information_line.filtered(lambda x: x.type == 'hadits').read()
info = [] if not company.information_line else company.information_line.filtered(lambda x: x.type == 'info').read()
max_len = max([len(quran), len(hadits), len(info)])
information = ''
for row in range(max_len):
separator = '' if not information else ' | '
if row < len(quran):
information += '%s%s' % (separator, quran[row].get('name'))
separator = ' | '
if row < len(hadits):
information += '%s%s' % (separator, hadits[row].get('name'))
separator = ' | '
if row < len(info):
information += '%s%s' % (separator, info[row].get('name'))
separator = ' | '
####
result = {
'company': company.read()[0],
'adjustment': {} if not company.partner_id.city_id else company.partner_id.city_id.read()[0],
'background': [] if not company.background_line else company.background_line.read(),
'info': information,
}
return result

Kemudian compile dan upgrade addonsnya. Berikut hasilnya:


Masih ada fitur - fitur yang lain yang belum saya jelaskan, detailnya bisa langsung dilihat di source code yang fullnya ya di pembahasan fungsional aplikasi ini.

Aplikasi jadwal sholat ini masih bisa dikembangkan lagi untuk menambahkan fitur - fitur yang lain seperti waktu iqomah yang dibuat berbeda setiap waktu sholat, memunculkan tampilan waktu mundur atau peringatan ketika sudah masuk waktu sholat atau waktu khutbah jum'at, dan yang lainnya.

Terima kasih, semoga bermanfaat.
Kahfi
Wassalamu'alaikum Warohmatullah Wabarokatuh

 




Custom Template Email Default Odoo