📜 ⬆️ ⬇️

HabraKarma - writing an application in Python for s60

image After we warmed up the appetite for Python for s60 and started learning to write applications, I want to suggest continuing to comprehend programming for symbain in the wonderful programming language python.

This time we will do something useful, namely, we will write an application that will show karma. Do not just show, but display on top of all the “windows” a sign, on which will be the value of karma and the difference with the previous value. In addition, the program will publish a victorious gong with an increase in karma and a cry of despair as it decreases. Everything else, we run it as a server, that is, it will not appear in the list of running programs.

For those who are more important result than the process, welcome to the end of the article, where you expect a ready application HabraKarma 1.0 !!!

This time, I will not comment on every line in the program. I mean that you are at least a little familiar with python, know how to read the documentation , and at least understand something from my previous article .
')

General principles of work


The program itself will consist of 2 parts: the server itself, which does all the work, and the GUI, in which we will configure the server, start it and stop it.

The server itself is started by the start_server function from the e32 module. The function has only one parameter - the full path to the Python script, which should be run as a server. Yes, yes, everything is so simple, but with some restrictions.

Since the server is running in the background, it cannot use the appuifw UI module. But we don’t need it, because we’ll show the result of work using the topwindow module, which allows you to display images on top of all the “windows”. In addition, another module is available to us, called globalui, which also allows you to display such things as various requests, warnings, notifications, etc. on top of all the “windows”. This will also be used to demonstrate the start and stop of the server.

Another limitation is the inability to access files located in the application folder (x: / private / UID). Therefore, if we want to use various multimedia files, configuration files, we need to put it in some neutral place, for example, in the x: / system / data / AppName folder. This folder has the attribute "hidden", so the pictures placed there will not be visible in the gallery, and the audio files in the library.

Another problem is the “isolation” of the server from the main program. That is, we can start it, but it is impossible to find out whether it is running or to stop when using standard modules. In our program we will proceed as follows:

The server, when launched, creates a file with the name habra_flag in the root of drive D. When the server is shut down, this file will be deleted. Now, when starting the shell, check if the file you are searching for exists. If yes, then the server is considered running. In addition, you need the ability to stop the server. For this, in this very file we will write down something, and on the server, in a loop, we will check. If the file is longer than zero, stop the work.

Some may have a question, what kind of disk D, to which we are going to write the file habra_flag. This is a ram disk, of small volume, which is cleared on reboot Using it, we kill two birds with one stone: when you restart the phone, manually shut down our server, the flag file will disappear, and the file system on the ram disk has great performance. For more complex interaction with the server, you can use sockets.

Writing UI


The muzzle of the application, which will be launched by clicking on the program icon, will be the Form class, which is practically completely described in this wiki article . It looks like this:

image

And here is the program code itself with my comments:

  1. #coding: utf-8
  2. from appuifw import *
  3. import e32
  4. import os
  5. # folder in which settings files, media files, etc. are located.
  6. data_path = os . getcwd ( ) [ 0 ] + u ': \\ System \\ data \\ HabraKarma \\ '
  7. class Main:
  8. def __init__ ( self ) :
  9. app. screen = 'normal'
  10. # read the settings file, which is a dictionary,
  11. # stupidly saved via repr :)
  12. self . settings = eval ( open ( data_path + 'set.dat' ) . read ( ) )
  13. # List of fields for our form, insert the saved values ​​into its fields.
  14. self . fields = [
  15. ( u 'Habrayuzer' , 'text' , self . settings [ 'user' ] ) ,
  16. ( u "Auto update (min.)" , 'number' , self . settings [ 'time' ] ) ,
  17. ( u "Enable sound?" , 'combo' , ( [ u 'Yes' , u 'No' ] , int ( self . settings [ 'sound' ] ) ) ) ,
  18. ( u "Count the difference" , 'combo' , ( [ u 'Since the beginning of work' , u 'Since last update' ] , int ( self . settings [ 'diff' ] ) ) )
  19. ( u "Position X" , 'number' , self . settings [ 'X' ] ) ,
  20. ( u "Position Y" , 'number' , self . settings [ 'Y' ] ) ,
  21. ]
  22. # create a form with flags
  23. self . form = Form ( self . fields , flags = FFormDoubleSpaced | FFormEditModeOnly )
  24. # set the function that will save the values ​​from the form
  25. self . form . save_hook = self . save
  26. # if the server is already running, then the menu should be "stop" and vice versa
  27. if os . path . exists ( u 'd: \\ habra_flag' ) :
  28. self . form . menu = [ ( u 'Stop' , self . stop ) ]
  29. else :
  30. self . form . menu = [ ( u 'Run' , self . start_server ) ]
  31. # "execute" the form, that is, it will be displayed on the screen, as long as
  32. # we will not leave it.
  33. self . form . execute ( )
  34. # after exiting the form, check if the server is running and suggest to start it
  35. if not os . path . exists ( u 'd: \\ habra_flag' ) :
  36. if query ( u 'Run?' , 'query' ) :
  37. self . start_server ( )
  38. def start_server ( self ) :
  39. # actually server startup function
  40. self . form . menu = [ ( u 'Stop' , self . stop ) ]
  41. e32. start_server ( data_path + 'server.py' )
  42. def stop ( self ) :
  43. # server stop function.
  44. self . form . menu = [ ( u 'Run' , self . start_server ) ]
  45. open ( u 'd: \\ habra_flag' , 'w' ) . write ( 'stop' )
  46. def save ( self , arg = None ) :
  47. # take values ​​from the form and save them to the settings file.
  48. self . settings [ 'user' ] = arg [ 0 ] [ 2 ]
  49. self . settings [ 'time' ] = arg [ 1 ] [ 2 ]
  50. self . settings [ 'sound' ] = arg [ 2 ] [ 2 ] [ 1 ]
  51. self . settings [ 'diff' ] = arg [ 3 ] [ 2 ] [ 1 ]
  52. self . settings [ 'X' ] = arg [ 4 ] [ 2 ]
  53. self . settings [ 'Y' ] = arg [ 5 ] [ 2 ]
  54. open ( data_path + 'set.dat' , 'w' ) . write ( repr ( self . settings ) )
  55. return true
  56. a = Main ( )


It remains to write the server :)



  1. # - * - coding: utf-8 - * -
  2. import os
  3. import e32
  4. import sys
  5. # redirect errors to the file.
  6. sys . stderr = open ( 'd: \\ err.txt' , 'w' )
  7. import globalui as ui
  8. import topwindow
  9. from graphics import *
  10. import urllib
  11. import audio
  12. open ( u 'd: \\ habra_flag' , 'w' ) . write ( '' )
  13. data_path = os . getcwd ( ) [ 0 ] + u ': \\ System \\ data \\ HabraKarma \\ '
  14. # show that we started.
  15. ui. global_note ( u 'Habrastart!' )
  16. class Habra:
  17. def __init__ ( self ) :
  18. # open images
  19. self . habr_img = Image. open ( data_path + 'habr.png' )
  20. self . update_img = Image. open ( data_path + 'update.png' )
  21. # read settings
  22. self . settings = eval ( open ( data_path + 'set.dat' ) . read ( ) )
  23. self . last_karma = eval ( open ( data_path + 'karma.dat' ) . read ( ) )
  24. # open sound
  25. self . bad_sound = audio. Sound . open ( data_path + 'bad.wav' )
  26. self . good_sound = audio. Sound . open ( data_path + 'good.wav' )
  27. self . loop = True
  28. # create a TopWindow window
  29. self . top = topwindow. TopWindow ( )
  30. # specify rounding
  31. self . top . corner_type = 'corner5'
  32. self . top . size = ( 170 , 35 )
  33. # set the position from the settings file
  34. self . top . position = ( self . settings [ 'X' ] , self . settings [ 'Y' ] )
  35. self . top . show ( )
  36. self . karma_screen ( )
  37. self . mainloop ( )
  38. def stop ( self ) :
  39. self . loop = False
  40. self . top . hide ( )
  41. def karma_screen ( self ) :
  42. # function called for update
  43. self . update_screen ( )
  44. e32. ao_sleep ( 0.2 )
  45. # pull info from harba api
  46. data = urllib . urlopen ( 'http://habrahabr.ru/api/profile/' + self . settings [ 'user' ] ) . read ( )
  47. # they probably stumble me, but I don't want to drag it
  48. # case library for parsing xml
  49. karma = float ( data. split ( '<karma>' ) [ 1 ] . split ( '</ karma>' ) [ 0 ] )
  50. # compare new karma with old and
  51. # depending on the situation, collect the text, specify the color
  52. # and play the sound, if it is set in the settings
  53. if self . last_karma < karma:
  54. karma_diff = u '(+' + str ( abs ( self . last_karma -karma ) ) + u ')'
  55. karma_color = 0x009f31
  56. if not self . settings [ 'sound' ] :
  57. self . good_sound . play ( )
  58. elif self . last_karma > karma:
  59. karma_diff = u '(-' + str ( abs ( self . last_karma -karma ) ) + u ')'
  60. karma_color = 0xc30202
  61. if not self . settings [ 'sound' ] :
  62. self . bad_sound . play ( )
  63. else :
  64. karma_diff = u ''
  65. karma_color = 0xffffff
  66. if self . settings [ 'diff' ] :
  67. self . last_karma = karma
  68. open ( data_path + 'karma.dat' , 'w' ) . write ( repr ( karma ) )
  69. # here we will find out how many pixels the width of the text to occupy
  70. karma_width = self . img . measure_text ( unicode ( karma ) ) [ 0 ] [ 2 ]
  71. diff_width = self . img . measure_text ( karma_diff ) [ 0 ] [ 2 ]
  72. # and then the matter of technology :)
  73. self . img = Image. new ( ( 45 + karma_width + diff_width, 35 ) )
  74. self . top . size = ( self . img . size [ 0 ] , 35 )
  75. self . img . text ( ( 35 , 25 ) , unicode ( karma ) )
  76. self . img . text ( ( 35 + karma_width + 5 , 25 ) , karma_diff, fill = karma_color )
  77. self . img . blit ( self . habr_img )
  78. self . top . add_image ( self . img , ( 0 , 0 ) )
  79. def update_screen ( self ) :
  80. # this will be displayed during the update
  81. self . img = Image. new ( ( 165 , 35 ) )
  82. self . top . size = ( self . img . size [ 0 ] , 35 )
  83. self . img . blit ( self . update_img )
  84. self . img . text ( ( 35 , 25 ) , u 'Updated' )
  85. self . top . add_image ( self . img , ( 0 , 0 ) )
  86. def mainloop ( self ) :
  87. # and let the main server loop
  88. interval = self . settings [ 'time' ] * 60
  89. count = 0
  90. while self . loop :
  91. # if we are ordered to stop the server
  92. if open ( u 'd: \\ habra_flag' ) . read ( ) :
  93. os . remove ( u 'd: \\ habra_flag' )
  94. ui. global_note ( u 'Habrastop!' )
  95. self . loop = False
  96. count + = 1
  97. # if the time is right, we expose karma.
  98. if count > interval:
  99. count = 0
  100. self . karma_screen ( )
  101. e32. ao_sleep ( 1 )
  102. habr = Habra ( )


It remains to collect the whole thing in sis and watch the karma :)

Sources, along with pictures, sounds, an icon can be taken HERE . In ensymble in the build options to register:
--extrasdir = data --lang = RU --icon = path_to_connect

And take the result ...


So, I present to your attention the application HabraKarma for symbain 9.x
Install the application, enter your username, configure the update time, the position of the window. Now you can start the server, which will display your karma on top of all windows. After that, the program can be closed, the window will remain until you turn it off by going back to the program.
Download from here (sis, 56 kb, does not require a signature)
Do not forget that the work requires Python Runtime at least version 1.9.7 ( download ).
Python and the program to put on the same disk!

Source: https://habr.com/ru/post/77452/


All Articles