Последнюю неделю я программировал с помощью Kivy и KivyMD и пытался разработать приложение с селектором изображений. Проблема, с которой я столкнулся, заключается в том, что независимо от того, что я использую, оно не отображает медиафайлы моего телефона и не запрашивает разрешение на доступ.
Я использую FileChooserIconView для создания нового экрана, на котором отображается файлы телефона. Я попробовал использовать этот код в on_start MDApp:
if platform == 'android':
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.READ_MEDIA_IMAGES])
но он продолжает показывать только папки, а не файлы.
Я хочу, чтобы он показывал все, а пока он показывает только папки.
Это main.py:
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.label import MDLabel
from kivy.uix.image import Image
from kivy.uix.gridlayout import GridLayout
from kivy import platform
import json
import os
import unicodedata
class MainScreen(MDScreen):
def normalizar_texto(self, texto):
# Normaliza el texto: elimina tildes y convierte a minúsculas
texto_sin_tildes = unicodedata.normalize('NFKD', texto).encode('ASCII', 'ignore').decode('utf-8')
return texto_sin_tildes.lower().strip()
def load_beasts(self):
# Load characters from a JSON file and add them to the screen
if os.path.exists('beasts.json'):
with open('beasts.json', 'r') as f:
beasts = json.load(f)
return beasts
else:
return [{"id": 0, "name": "Error", "image": "", "description": "No existe archivo"}]
def on_search_button(self):
# Get the text from TextInput when the button is pressed
search_text = self.ids.search_input.text
dex = self.load_beasts()
if search_text.strip().isdigit():
result = [beast for beast in dex if beast['id'] == int(search_text)]
elif self.normalizar_texto(search_text) == 'abel':
result = [{"id": "???", "image": "images/abel.jpeg","name": "Abel Cid Outlaw",
"description": "La criatura más cruel y despiadada de todo el multiverso. No teme a nada, no aprecia a nadie. Solo desea ver como el mundo arde bajo sus pies."}]
else:
result = [beast for beast in dex if self.normalizar_texto(beast['name']) == self.normalizar_texto(search_text)]
if result:
self.mostrar_informacion(result[0])
def mostrar_informacion(self, beast):
# Asumimos que hay etiquetas para mostrar los datos en la interfaz
self.ids.name_label.text = f"{beast['id']}. {beast['name']}"
self.ids.beast_img.source = beast['image']
self.ids.beast_img.height = 500
#self.ids.beast_img.reload()
self.ids.descrip_label.text= f"Descripción: {beast['description']}"
def load_beasts_db(self):
db_screen = self.manager.get_screen('db')
beasts = self.load_beasts()
for beast in beasts:
db_screen.add_beast_widget(beast)
class DBScreen(MDScreen):
def add_beast_widget(self, beast_data):
main_screen = self.manager.get_screen('main')
label = MDLabel(
text= f"{beast_data['id']}.{beast_data['name']}",
font_style="H5",
halign="center",
theme_text_color="Custom",
text_color= (0, 0, 0, 1)
)
img = Image(
source=beast_data['image'],
size=(200,200),
allow_stretch=True,
keep_ratio=False,
size_hint_y=None,
height=200
)
grid=GridLayout(
cols= 1,
spacing= 30,
padding= 20,
size_hint_y=None,
height=250
)
grid.add_widget(img)
grid.add_widget(label)
main_screen.ids.beast_list.add_widget(grid)
class AddScreen(MDScreen):
def open_file_chooser(self):
# Cambia a la pantalla de FileChooser
main_screen = self.manager.get_screen('main')
main_screen.ids.beast_name.text = main_screen.ids.beast_name.text
main_screen.ids.beast_description.text = main_screen.ids.beast_description.text
self.manager.current = "file_chooser"
def save_beast(self):
db_screen = self.manager.get_screen('db')
main_screen = self.manager.get_screen('main')
id = len(main_screen.load_beasts()) + 1
name = main_screen.ids.beast_name.text
image = main_screen.ids.image_display.source
description = main_screen.ids.beast_description.text
beast_data = {
'id': id,
'name': name,
'image': image,
'description': description
}
# Save character to the list
self.save_beasts_to_file(beast_data)
# Add button to the main screen dynamically
db_screen.add_beast_widget(beast_data)
# Clear the inputs after saving
main_screen.ids.beast_name.text = ''
main_screen.ids.image_display.source = ''
main_screen.ids.beast_description.text = ''
# Switch back to the main screen
self.manager.current = 'main'
def save_beasts_to_file(self, new_beast):
beasts = []
# Load existing characters from file if it exists
if os.path.exists('beasts.json'):
with open('beasts.json', 'r') as f:
beasts = json.load(f)
# Add the new character
beasts.append(new_beast)
# Save updated character list to file
with open('beasts.json', 'w') as f:
json.dump(beasts, f)
class FileChooserScreen(MDScreen):
def select_image(self, selection):
# Verifica si hay un archivo seleccionado
if selection:
main_screen = self.manager.get_screen("main")
main_screen.ids.image_display.source = selection[0]
self.manager.current = "main"
class BeastDexApp(MDApp):
def on_start(self):
# Llama a load_beasts_db solo al iniciar la aplicación
main_screen = self.root.get_screen('main')
main_screen.load_beasts_db()
if platform == 'android':
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.READ_MEDIA_IMAGES])
def build(self):
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(DBScreen(name='db'))
sm.add_widget(AddScreen(name='add'))
sm.add_widget(FileChooserScreen(name='file_chooser'))
return sm
if __name__ == '__main__':
BeastDexApp().run()
Это файл .kv:
#:import platform kivy.utils.platform
:
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
size: self.size
pos: self.pos
source: 'img.jpg'
MDNavigationLayout:
MDScreenManager:
id: screen_manager
MDScreen:
# Main background image
name: 'main'
FloatLayout:
# Menu icon
MDIconButton:
icon: "menu"
pos_hint: {"center_x": 0.05, "center_y": 0.95}
on_release: nav_drawer.set_state("toggle")
MDLabel:
text: 'BeastDex'
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
font_style: "H1"
pos_hint: {'top': 0.95, 'center_x': 0.5}
halign: "center"
font_name: 'Amores Free Font.ttf'
size_hint_y: None
height: dp(60)
# Main content layout
BoxLayout:
orientation: 'vertical'
padding: [20, 200, 20, 20]
spacing: dp(20)
size_hint_y: 1
# Search bar layout
BoxLayout:
orientation: 'horizontal'
padding: dp(10)
spacing: dp(10)
size_hint_y: None
height: dp(50)
MDTextField:
id: search_input
hint_text: "Buscar bestia"
size_hint_x: 0.8
height: dp(50)
multiline: False
MDRaisedButton:
text: "Search"
size_hint_x: 0.2
height: dp(50)
on_release: root.on_search_button()
# Data layout for result display
ScrollView:
do_scroll_x: False
GridLayout:
cols: 1
spacing: dp(30)
padding: dp(20)
size_hint_y: None
height: self.minimum_height
# Display name label
MDLabel:
id: name_label
text: ""
font_style: "H5"
halign: "center"
theme_text_color: "Custom"
text_color: 0, 0, 0, 1
# Beast image display
Image:
id: beast_img
source: ''
size_hint_y: None
height: 0
allow_stretch: True
keep_ratio: True
# Description label
MDLabel:
id: descrip_label
text: ""
font_style: "Body1"
halign: "center"
theme_text_color: "Custom"
text_color: 0, 0, 0, 1
MDScreen:
name: 'db'
BoxLayout:
orientation: 'vertical'
MDIconButton:
icon: "menu"
pos_hint: {"center_x": 0.05, "center_y": 0.95}
on_release: nav_drawer.set_state("toggle")
MDLabel:
text: 'BeastDex'
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
font_style: "H1"
pos_hint: {'top': 0.95, 'center_x': 0.5}
halign: "center"
font_name: 'Amores Free Font.ttf'
size_hint_y: None
height: dp(60)
ScrollView:
do_scroll_x: False # Disable horizontal scrolling if not needed
GridLayout:
id: beast_list
cols: 2
spacing: dp(10)
padding: [dp(40), ]
size_hint_y: None
height: self.minimum_height
MDScreen:
name: 'add'
BoxLayout:
orientation: 'vertical'
MDIconButton:
icon: "menu"
pos_hint: {"center_x": 0.05, "center_y": 0.95}
on_release: nav_drawer.set_state("toggle")
MDLabel:
text: 'BeastDex'
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
font_style: "H1"
pos_hint: {'top': 0.95, 'center_x': 0.5}
halign: "center"
font_name: 'Amores Free Font.ttf'
size_hint_y: None
height: dp(60)
ScrollView:
size_hint: 1, 0.85 # Make it take up the remaining space
pos_hint: {'top': 0.85}
do_scroll_x: False # Disable horizontal scrolling
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: [20, 20, 20, 20] # Add some padding for spacing
spacing: 20 # Add some space between elements
Label:
text: 'Nombre'
color: 0, 0, 0, 1
halign: "center"
TextInput:
id: beast_name
hint_text: ""
multiline: False
size_hint_y: None
height: 60
Label:
text: 'Imagen'
color: 0, 0, 0, 1
halign: "center"
MDRaisedButton:
text: "Seleccionar Imagen"
pos_hint: {"center_x": 0.5}
on_release: app.root.get_screen('add').open_file_chooser()
Image:
id: image_display
source: ""
size_hint_y: None
height: 50
allow_stretch: True
keep_ratio: True
Label:
text: 'Descripción'
color: 0, 0, 0, 1
halign: "center"
TextInput:
id: beast_description
hint_text: ""
multiline: False
size_hint_y: None
height: 60
Button:
text: "Save Beast"
size_hint_y: None
height: 70
on_release: app.root.get_screen('add').save_beast()
MDNavigationDrawer:
id: nav_drawer
BoxLayout:
orientation: 'vertical'
size_hint_y: None
spacing: 10
height: self.minimum_height # Asegura que el tamaño se ajuste al contenido
pos_hint: {'top': 1}
MDLabel:
text: "Enciclopedia:\n Las Bestias del Multiverso"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1
halign: 'center'
font_style: 'H6'
size_hint_y: None
height: self.texture_size[1]
# Línea separadora
Widget:
size_hint_y: None
height: dp(3) # Altura de la línea separadora
canvas:
Color:
rgba: 0.7, 0.7, 0.7, 1 # Color de la línea
Rectangle:
size: self.size
pos: self.pos
MDList:
OneLineIconListItem:
text: "Buscador"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1.0
on_release:
nav_drawer.set_state("close")
screen_manager.current = 'main'
OneLineIconListItem:
text: "Todas las Bestias"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1.0
on_release:
nav_drawer.set_state("close")
screen_manager.current = 'db'
OneLineIconListItem:
text: "Añadir Bestia"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1.0
on_release:
nav_drawer.set_state("close")
screen_manager.current = 'add'
:
BoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1 # Color de fondo (modifícalo a tu gusto)
Rectangle:
pos: self.pos
size: self.size
FileChooserIconView:
rootpath: '/storage/emulated/0/' if platform == 'android' else '/'
id: filechooser
on_selection: root.select_image(filechooser.selection)
Подробнее здесь: https://stackoverflow.com/questions/791 ... to-android
Разрешения на доступ к мультимедиа Python для Android ⇐ Android
Форум для тех, кто программирует под Android
-
Anonymous
1730952011
Anonymous
Последнюю неделю я программировал с помощью Kivy и KivyMD и пытался разработать приложение с селектором изображений. Проблема, с которой я столкнулся, заключается в том, что независимо от того, что я использую, оно не отображает медиафайлы моего телефона и не запрашивает разрешение на доступ.
Я использую FileChooserIconView для создания нового экрана, на котором отображается файлы телефона. Я попробовал использовать этот код в on_start MDApp:
if platform == 'android':
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.READ_MEDIA_IMAGES])
но он продолжает показывать только папки, а не файлы.
Я хочу, чтобы он показывал все, а пока он показывает только папки.
Это main.py:
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.label import MDLabel
from kivy.uix.image import Image
from kivy.uix.gridlayout import GridLayout
from kivy import platform
import json
import os
import unicodedata
class MainScreen(MDScreen):
def normalizar_texto(self, texto):
# Normaliza el texto: elimina tildes y convierte a minúsculas
texto_sin_tildes = unicodedata.normalize('NFKD', texto).encode('ASCII', 'ignore').decode('utf-8')
return texto_sin_tildes.lower().strip()
def load_beasts(self):
# Load characters from a JSON file and add them to the screen
if os.path.exists('beasts.json'):
with open('beasts.json', 'r') as f:
beasts = json.load(f)
return beasts
else:
return [{"id": 0, "name": "Error", "image": "", "description": "No existe archivo"}]
def on_search_button(self):
# Get the text from TextInput when the button is pressed
search_text = self.ids.search_input.text
dex = self.load_beasts()
if search_text.strip().isdigit():
result = [beast for beast in dex if beast['id'] == int(search_text)]
elif self.normalizar_texto(search_text) == 'abel':
result = [{"id": "???", "image": "images/abel.jpeg","name": "Abel Cid Outlaw",
"description": "La criatura más cruel y despiadada de todo el multiverso. No teme a nada, no aprecia a nadie. Solo desea ver como el mundo arde bajo sus pies."}]
else:
result = [beast for beast in dex if self.normalizar_texto(beast['name']) == self.normalizar_texto(search_text)]
if result:
self.mostrar_informacion(result[0])
def mostrar_informacion(self, beast):
# Asumimos que hay etiquetas para mostrar los datos en la interfaz
self.ids.name_label.text = f"{beast['id']}. {beast['name']}"
self.ids.beast_img.source = beast['image']
self.ids.beast_img.height = 500
#self.ids.beast_img.reload()
self.ids.descrip_label.text= f"Descripción: {beast['description']}"
def load_beasts_db(self):
db_screen = self.manager.get_screen('db')
beasts = self.load_beasts()
for beast in beasts:
db_screen.add_beast_widget(beast)
class DBScreen(MDScreen):
def add_beast_widget(self, beast_data):
main_screen = self.manager.get_screen('main')
label = MDLabel(
text= f"{beast_data['id']}.{beast_data['name']}",
font_style="H5",
halign="center",
theme_text_color="Custom",
text_color= (0, 0, 0, 1)
)
img = Image(
source=beast_data['image'],
size=(200,200),
allow_stretch=True,
keep_ratio=False,
size_hint_y=None,
height=200
)
grid=GridLayout(
cols= 1,
spacing= 30,
padding= 20,
size_hint_y=None,
height=250
)
grid.add_widget(img)
grid.add_widget(label)
main_screen.ids.beast_list.add_widget(grid)
class AddScreen(MDScreen):
def open_file_chooser(self):
# Cambia a la pantalla de FileChooser
main_screen = self.manager.get_screen('main')
main_screen.ids.beast_name.text = main_screen.ids.beast_name.text
main_screen.ids.beast_description.text = main_screen.ids.beast_description.text
self.manager.current = "file_chooser"
def save_beast(self):
db_screen = self.manager.get_screen('db')
main_screen = self.manager.get_screen('main')
id = len(main_screen.load_beasts()) + 1
name = main_screen.ids.beast_name.text
image = main_screen.ids.image_display.source
description = main_screen.ids.beast_description.text
beast_data = {
'id': id,
'name': name,
'image': image,
'description': description
}
# Save character to the list
self.save_beasts_to_file(beast_data)
# Add button to the main screen dynamically
db_screen.add_beast_widget(beast_data)
# Clear the inputs after saving
main_screen.ids.beast_name.text = ''
main_screen.ids.image_display.source = ''
main_screen.ids.beast_description.text = ''
# Switch back to the main screen
self.manager.current = 'main'
def save_beasts_to_file(self, new_beast):
beasts = []
# Load existing characters from file if it exists
if os.path.exists('beasts.json'):
with open('beasts.json', 'r') as f:
beasts = json.load(f)
# Add the new character
beasts.append(new_beast)
# Save updated character list to file
with open('beasts.json', 'w') as f:
json.dump(beasts, f)
class FileChooserScreen(MDScreen):
def select_image(self, selection):
# Verifica si hay un archivo seleccionado
if selection:
main_screen = self.manager.get_screen("main")
main_screen.ids.image_display.source = selection[0]
self.manager.current = "main"
class BeastDexApp(MDApp):
def on_start(self):
# Llama a load_beasts_db solo al iniciar la aplicación
main_screen = self.root.get_screen('main')
main_screen.load_beasts_db()
if platform == 'android':
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.READ_MEDIA_IMAGES])
def build(self):
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(DBScreen(name='db'))
sm.add_widget(AddScreen(name='add'))
sm.add_widget(FileChooserScreen(name='file_chooser'))
return sm
if __name__ == '__main__':
BeastDexApp().run()
Это файл .kv:
#:import platform kivy.utils.platform
:
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
size: self.size
pos: self.pos
source: 'img.jpg'
MDNavigationLayout:
MDScreenManager:
id: screen_manager
MDScreen:
# Main background image
name: 'main'
FloatLayout:
# Menu icon
MDIconButton:
icon: "menu"
pos_hint: {"center_x": 0.05, "center_y": 0.95}
on_release: nav_drawer.set_state("toggle")
MDLabel:
text: 'BeastDex'
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
font_style: "H1"
pos_hint: {'top': 0.95, 'center_x': 0.5}
halign: "center"
font_name: 'Amores Free Font.ttf'
size_hint_y: None
height: dp(60)
# Main content layout
BoxLayout:
orientation: 'vertical'
padding: [20, 200, 20, 20]
spacing: dp(20)
size_hint_y: 1
# Search bar layout
BoxLayout:
orientation: 'horizontal'
padding: dp(10)
spacing: dp(10)
size_hint_y: None
height: dp(50)
MDTextField:
id: search_input
hint_text: "Buscar bestia"
size_hint_x: 0.8
height: dp(50)
multiline: False
MDRaisedButton:
text: "Search"
size_hint_x: 0.2
height: dp(50)
on_release: root.on_search_button()
# Data layout for result display
ScrollView:
do_scroll_x: False
GridLayout:
cols: 1
spacing: dp(30)
padding: dp(20)
size_hint_y: None
height: self.minimum_height
# Display name label
MDLabel:
id: name_label
text: ""
font_style: "H5"
halign: "center"
theme_text_color: "Custom"
text_color: 0, 0, 0, 1
# Beast image display
Image:
id: beast_img
source: ''
size_hint_y: None
height: 0
allow_stretch: True
keep_ratio: True
# Description label
MDLabel:
id: descrip_label
text: ""
font_style: "Body1"
halign: "center"
theme_text_color: "Custom"
text_color: 0, 0, 0, 1
MDScreen:
name: 'db'
BoxLayout:
orientation: 'vertical'
MDIconButton:
icon: "menu"
pos_hint: {"center_x": 0.05, "center_y": 0.95}
on_release: nav_drawer.set_state("toggle")
MDLabel:
text: 'BeastDex'
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
font_style: "H1"
pos_hint: {'top': 0.95, 'center_x': 0.5}
halign: "center"
font_name: 'Amores Free Font.ttf'
size_hint_y: None
height: dp(60)
ScrollView:
do_scroll_x: False # Disable horizontal scrolling if not needed
GridLayout:
id: beast_list
cols: 2
spacing: dp(10)
padding: [dp(40), ]
size_hint_y: None
height: self.minimum_height
MDScreen:
name: 'add'
BoxLayout:
orientation: 'vertical'
MDIconButton:
icon: "menu"
pos_hint: {"center_x": 0.05, "center_y": 0.95}
on_release: nav_drawer.set_state("toggle")
MDLabel:
text: 'BeastDex'
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
font_style: "H1"
pos_hint: {'top': 0.95, 'center_x': 0.5}
halign: "center"
font_name: 'Amores Free Font.ttf'
size_hint_y: None
height: dp(60)
ScrollView:
size_hint: 1, 0.85 # Make it take up the remaining space
pos_hint: {'top': 0.85}
do_scroll_x: False # Disable horizontal scrolling
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: [20, 20, 20, 20] # Add some padding for spacing
spacing: 20 # Add some space between elements
Label:
text: 'Nombre'
color: 0, 0, 0, 1
halign: "center"
TextInput:
id: beast_name
hint_text: ""
multiline: False
size_hint_y: None
height: 60
Label:
text: 'Imagen'
color: 0, 0, 0, 1
halign: "center"
MDRaisedButton:
text: "Seleccionar Imagen"
pos_hint: {"center_x": 0.5}
on_release: app.root.get_screen('add').open_file_chooser()
Image:
id: image_display
source: ""
size_hint_y: None
height: 50
allow_stretch: True
keep_ratio: True
Label:
text: 'Descripción'
color: 0, 0, 0, 1
halign: "center"
TextInput:
id: beast_description
hint_text: ""
multiline: False
size_hint_y: None
height: 60
Button:
text: "Save Beast"
size_hint_y: None
height: 70
on_release: app.root.get_screen('add').save_beast()
MDNavigationDrawer:
id: nav_drawer
BoxLayout:
orientation: 'vertical'
size_hint_y: None
spacing: 10
height: self.minimum_height # Asegura que el tamaño se ajuste al contenido
pos_hint: {'top': 1}
MDLabel:
text: "Enciclopedia:\n Las Bestias del Multiverso"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1
halign: 'center'
font_style: 'H6'
size_hint_y: None
height: self.texture_size[1]
# Línea separadora
Widget:
size_hint_y: None
height: dp(3) # Altura de la línea separadora
canvas:
Color:
rgba: 0.7, 0.7, 0.7, 1 # Color de la línea
Rectangle:
size: self.size
pos: self.pos
MDList:
OneLineIconListItem:
text: "Buscador"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1.0
on_release:
nav_drawer.set_state("close")
screen_manager.current = 'main'
OneLineIconListItem:
text: "Todas las Bestias"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1.0
on_release:
nav_drawer.set_state("close")
screen_manager.current = 'db'
OneLineIconListItem:
text: "Añadir Bestia"
theme_text_color: 'Custom'
text_color: 0, 0, 0, 1.0
on_release:
nav_drawer.set_state("close")
screen_manager.current = 'add'
:
BoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1 # Color de fondo (modifícalo a tu gusto)
Rectangle:
pos: self.pos
size: self.size
FileChooserIconView:
rootpath: '/storage/emulated/0/' if platform == 'android' else '/'
id: filechooser
on_selection: root.select_image(filechooser.selection)
Подробнее здесь: [url]https://stackoverflow.com/questions/79156408/permissions-for-media-access-python-to-android[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия