data-sourcerer 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data_sourcerer-0.1.0.dist-info/METADATA +52 -0
- data_sourcerer-0.1.0.dist-info/RECORD +95 -0
- data_sourcerer-0.1.0.dist-info/WHEEL +5 -0
- data_sourcerer-0.1.0.dist-info/entry_points.txt +2 -0
- data_sourcerer-0.1.0.dist-info/licenses/LICENSE +21 -0
- data_sourcerer-0.1.0.dist-info/top_level.txt +1 -0
- sourcerer/__init__.py +15 -0
- sourcerer/domain/__init__.py +13 -0
- sourcerer/domain/access_credentials/__init__.py +7 -0
- sourcerer/domain/access_credentials/entities.py +53 -0
- sourcerer/domain/access_credentials/exceptions.py +17 -0
- sourcerer/domain/access_credentials/repositories.py +84 -0
- sourcerer/domain/access_credentials/services.py +91 -0
- sourcerer/domain/file_system/__init__.py +7 -0
- sourcerer/domain/file_system/entities.py +70 -0
- sourcerer/domain/file_system/exceptions.py +17 -0
- sourcerer/domain/file_system/services.py +64 -0
- sourcerer/domain/shared/__init__.py +6 -0
- sourcerer/domain/shared/entities.py +18 -0
- sourcerer/domain/storage_provider/__init__.py +7 -0
- sourcerer/domain/storage_provider/entities.py +86 -0
- sourcerer/domain/storage_provider/exceptions.py +17 -0
- sourcerer/domain/storage_provider/services.py +130 -0
- sourcerer/infrastructure/__init__.py +13 -0
- sourcerer/infrastructure/access_credentials/__init__.py +7 -0
- sourcerer/infrastructure/access_credentials/exceptions.py +16 -0
- sourcerer/infrastructure/access_credentials/registry.py +120 -0
- sourcerer/infrastructure/access_credentials/repositories.py +119 -0
- sourcerer/infrastructure/access_credentials/services.py +396 -0
- sourcerer/infrastructure/db/__init__.py +6 -0
- sourcerer/infrastructure/db/config.py +73 -0
- sourcerer/infrastructure/db/models.py +47 -0
- sourcerer/infrastructure/file_system/__init__.py +7 -0
- sourcerer/infrastructure/file_system/exceptions.py +89 -0
- sourcerer/infrastructure/file_system/services.py +147 -0
- sourcerer/infrastructure/storage_provider/__init__.py +7 -0
- sourcerer/infrastructure/storage_provider/exceptions.py +78 -0
- sourcerer/infrastructure/storage_provider/registry.py +84 -0
- sourcerer/infrastructure/storage_provider/services.py +509 -0
- sourcerer/infrastructure/utils.py +106 -0
- sourcerer/presentation/__init__.py +12 -0
- sourcerer/presentation/app.py +36 -0
- sourcerer/presentation/di_container.py +46 -0
- sourcerer/presentation/screens/__init__.py +0 -0
- sourcerer/presentation/screens/critical_error/__init__.py +0 -0
- sourcerer/presentation/screens/critical_error/main.py +78 -0
- sourcerer/presentation/screens/critical_error/styles.tcss +41 -0
- sourcerer/presentation/screens/file_system_finder/main.py +248 -0
- sourcerer/presentation/screens/file_system_finder/styles.tcss +44 -0
- sourcerer/presentation/screens/file_system_finder/widgets/__init__.py +0 -0
- sourcerer/presentation/screens/file_system_finder/widgets/file_system_navigator.py +810 -0
- sourcerer/presentation/screens/main/__init__.py +0 -0
- sourcerer/presentation/screens/main/main.py +469 -0
- sourcerer/presentation/screens/main/messages/__init__.py +0 -0
- sourcerer/presentation/screens/main/messages/delete_request.py +12 -0
- sourcerer/presentation/screens/main/messages/download_request.py +12 -0
- sourcerer/presentation/screens/main/messages/preview_request.py +10 -0
- sourcerer/presentation/screens/main/messages/resizing_rule.py +21 -0
- sourcerer/presentation/screens/main/messages/select_storage_item.py +11 -0
- sourcerer/presentation/screens/main/messages/uncheck_files_request.py +8 -0
- sourcerer/presentation/screens/main/messages/upload_request.py +10 -0
- sourcerer/presentation/screens/main/mixins/__init__.py +0 -0
- sourcerer/presentation/screens/main/mixins/resize_containers_watcher_mixin.py +144 -0
- sourcerer/presentation/screens/main/styles.tcss +32 -0
- sourcerer/presentation/screens/main/widgets/__init__.py +0 -0
- sourcerer/presentation/screens/main/widgets/gradient.py +45 -0
- sourcerer/presentation/screens/main/widgets/resizing_rule.py +67 -0
- sourcerer/presentation/screens/main/widgets/storage_content.py +691 -0
- sourcerer/presentation/screens/main/widgets/storage_list_sidebar.py +143 -0
- sourcerer/presentation/screens/preview_content/__init__.py +0 -0
- sourcerer/presentation/screens/preview_content/main.py +59 -0
- sourcerer/presentation/screens/preview_content/styles.tcss +26 -0
- sourcerer/presentation/screens/provider_creds_list/__init__.py +0 -0
- sourcerer/presentation/screens/provider_creds_list/main.py +164 -0
- sourcerer/presentation/screens/provider_creds_list/styles.tcss +65 -0
- sourcerer/presentation/screens/provider_creds_registration/__init__.py +0 -0
- sourcerer/presentation/screens/provider_creds_registration/main.py +264 -0
- sourcerer/presentation/screens/provider_creds_registration/styles.tcss +42 -0
- sourcerer/presentation/screens/question/__init__.py +0 -0
- sourcerer/presentation/screens/question/main.py +31 -0
- sourcerer/presentation/screens/question/styles.tcss +33 -0
- sourcerer/presentation/screens/shared/__init__.py +0 -0
- sourcerer/presentation/screens/shared/containers.py +13 -0
- sourcerer/presentation/screens/shared/widgets/__init__.py +0 -0
- sourcerer/presentation/screens/shared/widgets/button.py +54 -0
- sourcerer/presentation/screens/shared/widgets/labeled_input.py +80 -0
- sourcerer/presentation/screens/storage_action_progress/__init__.py +0 -0
- sourcerer/presentation/screens/storage_action_progress/main.py +476 -0
- sourcerer/presentation/screens/storage_action_progress/styles.tcss +43 -0
- sourcerer/presentation/settings.py +31 -0
- sourcerer/presentation/themes/__init__.py +0 -0
- sourcerer/presentation/themes/github_dark.py +21 -0
- sourcerer/presentation/utils.py +69 -0
- sourcerer/settings.py +72 -0
- sourcerer/utils.py +32 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
from textual.events import MouseMove, MouseUp
|
4
|
+
|
5
|
+
from sourcerer.presentation.screens.main.messages.resizing_rule import (
|
6
|
+
ResizingRuleSelect,
|
7
|
+
ResizingRuleRelease,
|
8
|
+
ResizingRuleMove,
|
9
|
+
)
|
10
|
+
from sourcerer.presentation.screens.main.widgets.resizing_rule import (
|
11
|
+
ResizingRule,
|
12
|
+
MoveEvent,
|
13
|
+
)
|
14
|
+
from sourcerer.presentation.settings import MIN_SECTION_DIMENSION
|
15
|
+
|
16
|
+
|
17
|
+
class ResizeContainersWatcherMixin:
|
18
|
+
"""
|
19
|
+
Watches and handles the resizing of containers in a user interface.
|
20
|
+
|
21
|
+
The ResizeContainersWatcher class provides functionality to manage and respond
|
22
|
+
to events related to resizing operations. It handles events for selecting,
|
23
|
+
moving, and releasing resizing rules, ensuring that the resizing operation is
|
24
|
+
properly executed and the state is consistently maintained. This class also
|
25
|
+
manages interactions like dragging and concludes resizing tasks when necessary.
|
26
|
+
|
27
|
+
Class should be used as a mixin in classes that require resizing functionality
|
28
|
+
and is inherited from textual App.
|
29
|
+
"""
|
30
|
+
|
31
|
+
required_methods = ["query_one", "refresh"]
|
32
|
+
|
33
|
+
def __init_subclass__(cls, **kwargs):
|
34
|
+
super().__init_subclass__(**kwargs)
|
35
|
+
|
36
|
+
for method in cls.required_methods:
|
37
|
+
if not hasattr(cls, method) or not callable(getattr(cls, method)):
|
38
|
+
raise TypeError(f"Class {cls.__name__} must implement method {method}")
|
39
|
+
|
40
|
+
def __init__(self, *args, **kwargs):
|
41
|
+
self.active_resizing_rule: ResizingRule | None = None
|
42
|
+
|
43
|
+
def on_resizing_rule_select(self, event: ResizingRuleSelect) -> None:
|
44
|
+
"""
|
45
|
+
Handle the selection of a resizing rule by updating the active resizing rule.
|
46
|
+
Called when the user press a resizing rule.
|
47
|
+
|
48
|
+
Arguments:
|
49
|
+
event (ResizingRuleSelect): The event containing the resizing rule id.
|
50
|
+
"""
|
51
|
+
self.active_resizing_rule = self.query_one(f"#{event.id}") # type: ignore
|
52
|
+
|
53
|
+
def on_resizing_rule_release(self, _: ResizingRuleRelease) -> None:
|
54
|
+
"""
|
55
|
+
Handle the release (completion) of the resizing rule.
|
56
|
+
|
57
|
+
This method is responsible for resetting the active resizing rule
|
58
|
+
back to None when a resizing operation is concluded. It ensures
|
59
|
+
that the system correctly cleans up and transitions out of the
|
60
|
+
resizing state.
|
61
|
+
|
62
|
+
Arguments:
|
63
|
+
_: The `ResizingRuleRelease` object that represents the
|
64
|
+
event or the logic related to ending the resizing operation.
|
65
|
+
"""
|
66
|
+
self.active_resizing_rule = None
|
67
|
+
|
68
|
+
def on_resizing_rule_move(self, event: ResizingRuleMove) -> None:
|
69
|
+
"""
|
70
|
+
Handles the resizing of components during a move event and updates their styles
|
71
|
+
accordingly. This method adjusts the width or height of the components involved
|
72
|
+
based on the orientation and the delta value from the event, ensuring minimum
|
73
|
+
dimensions are maintained. Refreshes the display after updating the styles.
|
74
|
+
|
75
|
+
Arguments:
|
76
|
+
event (ResizingRuleMove): The event containing the resizing rule details.
|
77
|
+
"""
|
78
|
+
|
79
|
+
prev_component = self.query_one(f"#{event.previous_component_id}") # type: ignore
|
80
|
+
next_component = self.query_one(f"#{event.next_component_id}") # type: ignore
|
81
|
+
|
82
|
+
dimension = "width" if event.orientation == "vertical" else "height"
|
83
|
+
|
84
|
+
previous_component_dimension = (
|
85
|
+
getattr(prev_component.styles, dimension).value + event.delta
|
86
|
+
)
|
87
|
+
next_component_dimension = (
|
88
|
+
getattr(next_component.styles, dimension).value - event.delta
|
89
|
+
)
|
90
|
+
|
91
|
+
if (
|
92
|
+
previous_component_dimension < MIN_SECTION_DIMENSION
|
93
|
+
or next_component_dimension < MIN_SECTION_DIMENSION
|
94
|
+
):
|
95
|
+
return
|
96
|
+
|
97
|
+
setattr(prev_component.styles, dimension, f"{previous_component_dimension}%")
|
98
|
+
setattr(next_component.styles, dimension, f"{next_component_dimension}%")
|
99
|
+
|
100
|
+
self.refresh() # type: ignore
|
101
|
+
|
102
|
+
def on_mouse_move(self, event: MouseMove) -> None:
|
103
|
+
"""
|
104
|
+
Handles mouse movement events to manage resizing operations based on the active resizing
|
105
|
+
rule. The function determines the change in position (delta) either horizontally or
|
106
|
+
vertically, depending on the orientation of the active resizing rule. If the resizing
|
107
|
+
rule is active and dragging is occurring, it updates the position accordingly.
|
108
|
+
|
109
|
+
Arguments:
|
110
|
+
event (MouseMove): The event containing the mouse movement details.
|
111
|
+
"""
|
112
|
+
|
113
|
+
if not self.active_resizing_rule or not self.active_resizing_rule.dragging:
|
114
|
+
return
|
115
|
+
|
116
|
+
try:
|
117
|
+
delta = (
|
118
|
+
event.delta_x
|
119
|
+
if self.active_resizing_rule.orientation == "vertical"
|
120
|
+
else event.delta_y
|
121
|
+
)
|
122
|
+
except AttributeError:
|
123
|
+
return # No delta
|
124
|
+
|
125
|
+
self.active_resizing_rule.position = MoveEvent(
|
126
|
+
timestamp=time.time(), delta=delta
|
127
|
+
)
|
128
|
+
|
129
|
+
def on_mouse_up(self, _: MouseUp) -> None:
|
130
|
+
"""
|
131
|
+
Handles the mouse-up event during a resizing rule interaction.
|
132
|
+
|
133
|
+
This method is invoked when the mouse-up event is detected. It checks if
|
134
|
+
there is an active resizing rule in operation. If such a rule exists, the
|
135
|
+
method ensures proper cleanup activities are performed and then clears the
|
136
|
+
active resizing rule, resetting it to None.
|
137
|
+
|
138
|
+
Arguments:
|
139
|
+
_: The `MouseUp` object that represents the mouse-up event.
|
140
|
+
"""
|
141
|
+
if not self.active_resizing_rule:
|
142
|
+
return
|
143
|
+
self.active_resizing_rule.cleanup()
|
144
|
+
self.active_resizing_rule = None
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
StorageListSidebar {
|
3
|
+
width: 20%;
|
4
|
+
}
|
5
|
+
|
6
|
+
StorageContent {
|
7
|
+
width: 80%;
|
8
|
+
}
|
9
|
+
|
10
|
+
#controls {
|
11
|
+
height: auto;
|
12
|
+
align-horizontal: center;
|
13
|
+
|
14
|
+
& > Button {
|
15
|
+
border: solid $primary;
|
16
|
+
width: 10;
|
17
|
+
content-align-horizontal: center;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
#header {
|
22
|
+
height: 3;
|
23
|
+
width: 100%;
|
24
|
+
color: white;
|
25
|
+
padding: 1 1 0 1;
|
26
|
+
}
|
27
|
+
|
28
|
+
Rule {
|
29
|
+
color: $background-lighten-3;
|
30
|
+
padding: 0 0;
|
31
|
+
margin: 0 0;
|
32
|
+
}
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from textual.widgets import Static
|
2
|
+
from rich.text import Text
|
3
|
+
|
4
|
+
|
5
|
+
def hex_to_rgb(hex_color: str):
|
6
|
+
"""
|
7
|
+
Convert a hex color string to an RGB tuple.
|
8
|
+
"""
|
9
|
+
hex_color = hex_color.lstrip("#")
|
10
|
+
return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
|
11
|
+
|
12
|
+
|
13
|
+
def generate_gradient_text(text: str, start_color: str, end_color: str) -> Text:
|
14
|
+
"""
|
15
|
+
Generate a gradient text effect by blending two colors across the text.
|
16
|
+
"""
|
17
|
+
start_rgb = hex_to_rgb(start_color)
|
18
|
+
end_rgb = hex_to_rgb(end_color)
|
19
|
+
|
20
|
+
gradient_text = Text()
|
21
|
+
|
22
|
+
for i, char in enumerate(text):
|
23
|
+
if len(text) > 1:
|
24
|
+
blend = i / (len(text) - 1)
|
25
|
+
else:
|
26
|
+
blend = 0
|
27
|
+
|
28
|
+
r = int(start_rgb[0] + (end_rgb[0] - start_rgb[0]) * blend)
|
29
|
+
g = int(start_rgb[1] + (end_rgb[1] - start_rgb[1]) * blend)
|
30
|
+
b = int(start_rgb[2] + (end_rgb[2] - start_rgb[2]) * blend)
|
31
|
+
|
32
|
+
color = f"#{r:02x}{g:02x}{b:02x}"
|
33
|
+
gradient_text.append(char, style=color)
|
34
|
+
|
35
|
+
return gradient_text
|
36
|
+
|
37
|
+
|
38
|
+
class GradientWidget(Static):
|
39
|
+
|
40
|
+
def on_mount(self):
|
41
|
+
"""
|
42
|
+
Generate a gradient text effect for the widget's content.
|
43
|
+
"""
|
44
|
+
gradient = generate_gradient_text(str(self.renderable), "#9E53E0", "#FFA656")
|
45
|
+
self.update(gradient)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
|
3
|
+
from textual.events import MouseDown, MouseUp
|
4
|
+
from textual.reactive import reactive
|
5
|
+
from textual.widgets import Rule
|
6
|
+
|
7
|
+
from sourcerer.presentation.screens.main.messages.resizing_rule import (
|
8
|
+
ResizingRuleMove,
|
9
|
+
ResizingRuleSelect,
|
10
|
+
ResizingRuleRelease,
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class MoveEvent:
|
16
|
+
timestamp: float
|
17
|
+
delta: int
|
18
|
+
|
19
|
+
|
20
|
+
class ResizingRule(Rule, can_focus=True):
|
21
|
+
dragging: reactive[bool] = reactive(False)
|
22
|
+
position: reactive[MoveEvent | None] = reactive(None)
|
23
|
+
|
24
|
+
def __init__(self, prev_component_id, next_component_id, *args, **kwargs):
|
25
|
+
super().__init__(*args, **kwargs)
|
26
|
+
if not kwargs.get("id"):
|
27
|
+
raise ValueError("ResizingRule must have an id")
|
28
|
+
self.prev_component_id = prev_component_id
|
29
|
+
self.next_component_id = next_component_id
|
30
|
+
|
31
|
+
def on_mouse_down(self, _: MouseDown) -> None:
|
32
|
+
"""Start dragging when the separator is clicked."""
|
33
|
+
self.dragging = True
|
34
|
+
self.post_message(ResizingRuleSelect(id=self.id)) # type: ignore
|
35
|
+
|
36
|
+
def on_mouse_up(self, _: MouseUp) -> None:
|
37
|
+
"""Stop dragging when mouse is released."""
|
38
|
+
self.cleanup()
|
39
|
+
|
40
|
+
def watch_position(self):
|
41
|
+
"""
|
42
|
+
Watch for changes in the position and post a ResizingRuleMove message if dragging is active.
|
43
|
+
"""
|
44
|
+
if not self.dragging:
|
45
|
+
return
|
46
|
+
|
47
|
+
if self.position is None:
|
48
|
+
return
|
49
|
+
|
50
|
+
self.post_message(
|
51
|
+
ResizingRuleMove(
|
52
|
+
delta=self.position.delta,
|
53
|
+
previous_component_id=self.prev_component_id,
|
54
|
+
next_component_id=self.next_component_id,
|
55
|
+
orientation=self.orientation,
|
56
|
+
)
|
57
|
+
)
|
58
|
+
|
59
|
+
def cleanup(self):
|
60
|
+
"""
|
61
|
+
Resets the dragging state and position, and posts a ResizingRuleRelease message to signal the end of a resize
|
62
|
+
operation.
|
63
|
+
"""
|
64
|
+
self.dragging = False
|
65
|
+
self.position = None
|
66
|
+
|
67
|
+
self.post_message(ResizingRuleRelease(id=self.id)) # type: ignore
|