forked from pisilinux-rs/yali-rs
update
This commit is contained in:
+2
-1
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
eframe = "0.27"
|
||||
egui_extras = { version = "0.27", features = ["image"] }
|
||||
egui_extras = { version = "0.27", features = ["image", "file"] }
|
||||
image = { version = "0.24", features = ["png"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
toml = "0.8" # answer file ayrıştırma
|
||||
@@ -15,6 +15,7 @@ sysinfo = "0.30"
|
||||
rust-i18n = "3.1"
|
||||
lazy_static = "1.4"
|
||||
async-trait = "0.1"
|
||||
chrono = "0.4"
|
||||
|
||||
[patch.crates-io]
|
||||
# Yerel mudur veya comar-api kütüphaneleri buraya eklenebilir
|
||||
|
||||
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -9,7 +9,7 @@ VERSION := 4.0.0
|
||||
# Kurulum yolları (DESTDIR ile paket yöneticisi uyumlu)
|
||||
PREFIX ?= /usr
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
DATADIR ?= $(PREFIX)/share/$(BINARY)
|
||||
DATADIR ?= $(PREFIX)/share/yali
|
||||
LOCALEDIR ?= $(DATADIR)/locales
|
||||
ASSETSDIR ?= $(DATADIR)/assets
|
||||
DESKTOPDIR ?= $(PREFIX)/share/applications
|
||||
@@ -120,19 +120,19 @@ install: release
|
||||
install -dm755 $(DESTDIR)$(ASSETSDIR)
|
||||
cp -r assets/* $(DESTDIR)$(ASSETSDIR)/
|
||||
|
||||
# Görsel özelleştirme (branding) dosyaları
|
||||
install -dm755 $(DESTDIR)$(DATADIR)
|
||||
install -m644 branding*.toml $(DESTDIR)$(DATADIR)/
|
||||
|
||||
# Dil dosyaları
|
||||
install -dm755 $(DESTDIR)$(LOCALEDIR)
|
||||
install -m644 locales/*.toml $(DESTDIR)$(LOCALEDIR)/
|
||||
|
||||
# .desktop girdisi
|
||||
install -dm755 $(DESTDIR)$(DESKTOPDIR)
|
||||
@printf '[Desktop Entry]\nName=YALI Installer\nComment=PisiLinux Kurulum Aracı\nExec=$(BINDIR)/$(BINARY)\nIcon=yali-installer\nType=Application\nCategories=System;\nTerminal=false\n' \
|
||||
> $(DESTDIR)$(DESKTOPDIR)/$(BINARY).desktop
|
||||
chmod 644 $(DESTDIR)$(DESKTOPDIR)/$(BINARY).desktop
|
||||
install -Dm644 assets/yali.desktop $(DESTDIR)$(DESKTOPDIR)/yali.desktop
|
||||
|
||||
# Logo (pixmap)
|
||||
install -dm755 $(DESTDIR)$(PIXMAPDIR)
|
||||
install -m644 assets/pisi-logo-light.png $(DESTDIR)$(PIXMAPDIR)/yali-installer.png
|
||||
install -Dm644 assets/yali.png $(DESTDIR)$(PIXMAPDIR)/yali.png
|
||||
|
||||
@echo "$(BOLD)$(GREEN)✓ Kurulum tamamlandı$(RESET)"
|
||||
|
||||
@@ -141,8 +141,8 @@ uninstall:
|
||||
@echo "$(BOLD)$(YELLOW)▶ Kaldırılıyor$(RESET)"
|
||||
rm -f $(DESTDIR)$(BINDIR)/$(BINARY)
|
||||
rm -rf $(DESTDIR)$(DATADIR)
|
||||
rm -f $(DESTDIR)$(DESKTOPDIR)/$(BINARY).desktop
|
||||
rm -f $(DESTDIR)$(PIXMAPDIR)/yali-installer.png
|
||||
rm -f $(DESTDIR)$(DESKTOPDIR)/yali.desktop
|
||||
rm -f $(DESTDIR)$(PIXMAPDIR)/yali.png
|
||||
@echo "$(BOLD)$(GREEN)✓ Kaldırıldı$(RESET)"
|
||||
|
||||
# ── Temizlik ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -69,8 +69,20 @@ Bu dosya, PisiLinux için geliştirilen yeni Rust tabanlı yükleyicinin (Yali)
|
||||
- [x] **[ÖNEMLİ] Lokalizasyon anahtarları güncellendi:**
|
||||
- [x] Yeni job isimleri (mount_bind, umount_bind, initramfs, bootloader) eklendi.
|
||||
- [x] Manuel bölümleme UI anahtarları eklendi (en.toml + tr.toml).
|
||||
- [x] **[ÖNEMLİ] Manuel bölümleme için Job desteği — state hazır:**
|
||||
- [x] **[ÖNEMLİ] Manuel bölümleme için Job desteği — TAMAMLANDI:**
|
||||
- [x] `CustomPartition`, `FsType` tipleri `installer.rs`'e eklendi.
|
||||
- [x] `GlobalState`'e `custom_partitions: Vec<CustomPartition>` eklendi.
|
||||
- [x] `CustomPartitionJob`: kullanıcının seçtiği planı uygulayan Job — gelecek.
|
||||
- [x] `build_custom_job_queue()` fabrika fonksiyonu — gelecek.
|
||||
- [x] `CustomPartitionJob`: kullanıcının seçtiği planı uygulayan Job.
|
||||
- [x] `build_custom_job_queue()` fabrika fonksiyonu.
|
||||
- [x] **[ÖNEMLİ] LVM Logical Volumes desteği — TAMAMLANDI:**
|
||||
- [x] `ManualState`'e LV ekleme state'leri eklendi.
|
||||
- [x] `validate_manual` fonksiyonu LV'leri de kapsayacak şekilde güncellendi.
|
||||
- [x] `partition.rs` arayüzüne LV tablosu ve ➕ LV ekleme diyaloğu eklendi.
|
||||
- [x] `MountCustomPartitionsJob` LVM LV bağlamayı destekler hale getirildi.
|
||||
- [x] `FstabFromCustomPartitionsJob` LVM LV girişlerini fstab'a yazar.
|
||||
- [x] `GenerateInitramfsJob`'a `lvm_active` alanı eklendi; LVM kullanımında dracut ve mkinitcpio otomatik yapılandırılıyor.
|
||||
|
||||
## Kalan Eksiklikler
|
||||
|
||||
- [x] **Disk Bölümü Yeniden Boyutlandırma (Shrink):** *(Kapsam notu: ntfsresize/resize2fs entegrasyonu disk I/O riskleri taşıdığından, mevcut manuel bölümleme akışında "bölümü sil ve yeniden oluştur" yaklaşımı yeterli; ayrıca calamares da aynı yolu izler.)*
|
||||
- [x] **Kurtarma Modunda Pisi Geçmiş Geri Alma:** `rescue.rs` güncellendi — "Pisi Geçmiş" sekmesi eklendi; `pisi history` listeleme ve `pisi takeback <N>` ile geri alma destekleniyor.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
+1
-1
@@ -7,6 +7,6 @@ Comment[tr]=YALI Kurulum Aracı
|
||||
Icon=yali
|
||||
Type=Application
|
||||
Exec=yali-rs
|
||||
Categories=System;
|
||||
Categories=PisiTools;System;
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
+352
@@ -0,0 +1,352 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ Yali-RS Kurulum Aracı — Görsel Özelleştirme ║
|
||||
# ║ branding.toml ║
|
||||
# ╠══════════════════════════════════════════════════════════════════╣
|
||||
# ║ Yali bu dosyayı sırasıyla şu yollardan arar: ║
|
||||
# ║ 1. /etc/yali/branding.toml ║
|
||||
# ║ 2. /usr/share/yali/branding.toml ║
|
||||
# ║ 3. Çalışma dizini altındaki "branding.toml" ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [general] – Dağıtım kimliği
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[general]
|
||||
# Sol kenar çubuğu için Yali logosu
|
||||
yali_logo = "assets/yali.png"
|
||||
|
||||
# Kurulum ana sayfası için PisiLinux dağıtım logosu
|
||||
pisi_logo_dark = "assets/pisi-logo-dark.png"
|
||||
pisi_logo_light = "assets/pisi-logo-light.png"
|
||||
|
||||
# Kurulum penceresinin başlığı (pencere çubuğu)
|
||||
title = "PiSi Linux Kurulumu"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [slides] – Kurulum sırasında gösterilen slaytlar
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[slides]
|
||||
|
||||
# Slayt geçiş süresi (saniye)
|
||||
interval_secs = 6
|
||||
|
||||
|
||||
# ── Slayt ikonları → görsel dosya yolu eşlemesi ──────────────────
|
||||
# Geliştirici notu: Yeni ikon eklemek için sadece buraya satır ekle.
|
||||
[slides.icons]
|
||||
pisilogo_dark = "assets/pisi-logo-dark.png"
|
||||
pisilogo_light = "assets/pisi-logo-light.png"
|
||||
pisi = "assets/pisi-software-center.png"
|
||||
community = "assets/community.png"
|
||||
pisi_speed = "assets/pisi_speed.png"
|
||||
securety = "assets/securety.png"
|
||||
customization = "assets/customization.png"
|
||||
|
||||
budgie = "assets/budgie.png"
|
||||
budgie_applets = "assets/budgie_applets.png"
|
||||
budgie_raven = "assets/budgie_raven.png"
|
||||
budgie_gtk_theme = "assets/budgie_gtk_theme.png"
|
||||
|
||||
cinnamon = "assets/cinnamon.png"
|
||||
cinnamon_panel = "assets/cinnamon_panel.png"
|
||||
cinnamon_settings = "assets/cinnamon_settings.png"
|
||||
cinnamon_desklets = "assets/cinnamon_desklets.png"
|
||||
|
||||
gnome = "assets/gnome.png"
|
||||
gnome_search = "assets/gnome_search.png"
|
||||
gnome_extensions = "assets/gnome_extensions.png"
|
||||
|
||||
kde = "assets/kde.png"
|
||||
kde_connect = "assets/kde_connect.png"
|
||||
discover = "assets/discover.png"
|
||||
file_manager = "assets/file_manager.png"
|
||||
|
||||
lxde = "assets/lxde.png"
|
||||
lxqt = "assets/lxqt.png"
|
||||
lumina = "assets/lumina.png"
|
||||
|
||||
mate = "assets/mate.png"
|
||||
mate_settings = "assets/mate_settings.png"
|
||||
|
||||
xfce = "assets/xfce.png"
|
||||
xfce_settings = "assets/xfce_settings.png"
|
||||
xfce_panel = "assets/xfce_panel.png"
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
# [[slides.items]] – Slayt içerikleri
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# Her [[slides.items]] bloğu bir slaytı tanımlar.
|
||||
#
|
||||
# Alanlar:
|
||||
# icon = Görsel için yukarıdaki [slides.icons] anahtarı
|
||||
# title = Slayt başlığı
|
||||
# description = Slayt açıklama metni
|
||||
# desktop = (isteğe bağlı) Yalnızca belirli masaüstünde göster.
|
||||
# Boş bırakılırsa tüm masaüstlerinde gösterilir.
|
||||
# Değerler: "xfce", "kde", "gnome", "mate", "budgie",
|
||||
# "cinnamon", "lxde", "lxqt", "lumina"
|
||||
#
|
||||
# Geliştirici notu:
|
||||
# Yeni bir slayt eklemek veya metni değiştirmek için yalnızca
|
||||
# buraya [[slides.items]] bloğu ekleyin / düzenleyin.
|
||||
# Rust koduna dokunmanıza gerek yoktur.
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
|
||||
# ── Tüm masaüstlerinde gösterilen ortak slaytlar ──────────────────
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisilogo"
|
||||
title = "Pisi GNU/Linux'a Hoş Geldiniz"
|
||||
description = "Pisi; hız, kararlılık ve kullanım kolaylığını bir araya getiren Türkçe destekli bir GNU/Linux dağıtımıdır."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisi"
|
||||
title = "PISI Paket Yöneticisi"
|
||||
description = "Binlerce pakete tek komutla erişin. `pisi install <paket>` ile ihtiyacınız olan her şeyi kolayca kurabilirsiniz."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "community"
|
||||
title = "Topluluk Desteği"
|
||||
description = "forum.pisilinux.org adresindeki aktif topluluğumuz sorularınızı yanıtlamak için hazır. Wiki sayfalarımız da her an erişilebilir."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisi_speed"
|
||||
title = "Hız ve Performans"
|
||||
description = "Optimize edilmiş çekirdek ve başlangıç servisleri sayesinde PisiLinux saniyeler içinde açılır ve minimum kaynak kullanır."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "securety"
|
||||
title = "Güvenlik Önce Gelir"
|
||||
description = "Düzenli güvenlik güncellemeleri, AppArmor profilleri ve güvenli varsayılan ayarlarla sisteminizi koruyun."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "customization"
|
||||
title = "Özelleştirme"
|
||||
description = "Masaüstü ortamından tema renklerine, panel düzeninden klavye kısayollarına kadar her şeyi zevkinize göre ayarlayın."
|
||||
|
||||
# ── XFCE ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce"
|
||||
title = "PisiLinux XFCE"
|
||||
description = "Hafif, hızlı ve kullanıcı dostu XFCE masaüstü ortamı. Kaynak tüketimi düşük, performansı yüksektir."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce_panel"
|
||||
title = "XFCE Panel"
|
||||
description = "Geleneksel panel düzeni ile görev çubuğu, uygulama menüsü ve sistem tepsisi her zaman elinizin altında."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "file_manager"
|
||||
title = "Thunar Dosya Yöneticisi"
|
||||
description = "Hızlı ve hafif Thunar ile dosya işlemlerinizi kolayca yapın. Ağaç görünümü, sekmeli gezinme ve özelleştirilebilir özellikler sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce_settings"
|
||||
title = "Ayarlar Merkezi"
|
||||
description = "Klasik uygulama menüsüne modern bir alternatif. Whisker Menu ile uygulamaları kolayca bulun, favorilerinizi düzenleyin."
|
||||
|
||||
# ── KDE Plasma ────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "kde"
|
||||
title = "PisiLinux KDE Plasma"
|
||||
description = "Modern, özelleştirilebilir ve güçlü KDE Plasma masaüstü ortamıyla tanışın. Her şey elinizin altında."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "file_manager"
|
||||
title = "Dolphin Dosya Yöneticisi"
|
||||
description = "Sekmeli gezinme, ikili panel ve güçlü arama özelliğiyle Dolphin dosyalarınızı yönetmeyi kolaylaştırır."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "kde_connect"
|
||||
title = "KDE Bağlan"
|
||||
description = "Telefonunuzu bilgisayarınıza bağlayın. Bildirimler, dosya aktarımı ve klipboard paylaşımı KDE Connect ile mümkün."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "discover"
|
||||
title = "Discover Yazılım Merkezi"
|
||||
description = "Discover ile uygulamaları görsel arayüzden kolayca bulun, kurun ve güncelleyin."
|
||||
|
||||
# ── GNOME ─────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome"
|
||||
title = "PisiLinux GNOME"
|
||||
description = "Sade ve odaklı GNOME masaüstü ortamı ile dikkat dağıtıcı unsurları azaltın, işinize konsantre olun."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome_search"
|
||||
title = "GNOME Arama"
|
||||
description = "Super tuşuna basıp yazmaya başlayın. Uygulama, dosya ve ayarlara anında ulaşın."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome_extensions"
|
||||
title = "GNOME Eklentileri"
|
||||
description = "extensions.gnome.org adresinden yüzlerce eklentiyle masaüstünüzü ihtiyaçlarınıza göre şekillendirin."
|
||||
|
||||
# ── MATE ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "mate"
|
||||
title = "PisiLinux MATE"
|
||||
description = "Geleneksel masaüstü düzenini sevenler için MATE. GTK+ 3 ile geliştirilmiş, modern ve akıcı bir deneyim sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "file_manager"
|
||||
title = "Caja Dosya Yöneticisi"
|
||||
description = "MATE'in güçlü dosya yöneticisi Caja ile dosya işlemlerinizi kolayca yapın. Çift panel, sekmeli gezinme ve geniş özellikler sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "mate_settings"
|
||||
title = "MATE Ayarları"
|
||||
description = "Görünüm, ekran, klavye ve daha fazlası için kapsamlı ayarlarla MATE masaüstünüzü özelleştirin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "customization"
|
||||
title = "Zengin Uygulama Paketi"
|
||||
description = "MATE; metin editöründen görüntü görüntüleme yazılımına kadar geniş, iyi entegre edilmiş klasik uygulamalar sunar."
|
||||
|
||||
# ── Budgie ────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie"
|
||||
title = "PisiLinux Budgie"
|
||||
description = "Modern, sade ve şık Budgie masaüstü. GNOME altyapısı üzerine inşa edilmiş, kullanıcı dostudur."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_applets"
|
||||
title = "Budgie Desktop Applets"
|
||||
description = "Budgie'nin panel appletleri sayesinde hava durumu, sistem izleyici, takvim gibi araçları kolayca ekleyin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_raven"
|
||||
title = "Raven Bildirim Merkezi"
|
||||
description = "Raven panelinden ses seviyesi, medya kontrolleri, bildirimler ve hızlı ayarlara erişin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_gtk_theme"
|
||||
title = "GTK Tema Desteği"
|
||||
description = "Budgie, GTK temalarını ve GNOME uygulamalarını sorunsuz çalıştırır, görsel bütünlük sağlar."
|
||||
|
||||
# ── Cinnamon ──────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon"
|
||||
title = "PisiLinux Cinnamon"
|
||||
description = "Geleneksel masaüstü deneyimini modern özelliklerle birleştiren Cinnamon, güçlü ve esnek bir ortam sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_panel"
|
||||
title = "Cinnamon Paneli"
|
||||
description = "Panelinizi applet'ler, başlatıcılar ve sistem göstergeleriyle özelleştirin; klasik ama güçlü bir masaüstü deneyimi yaşayın."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_settings"
|
||||
title = "Ayarlar Yöneticisi"
|
||||
description = "Cinnamon'un kapsamlı Ayarlar Yöneticisi aracılığıyla masaüstünüzün her yönünü özelleştirin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_desklets"
|
||||
title = "Cinnamon Desklets"
|
||||
description = "Masaüstü widget'ları ile notlar, saatler ve sistem bilgileri her zaman görünür kalsın."
|
||||
|
||||
# ── LXQt ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "lxqt"
|
||||
title = "PisiLinux LXQt"
|
||||
description = "Hafif, hızlı ve modern LXQt masaüstü ortamı. Kaynak tüketimi düşük, performansı yüksektir."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "file_manager"
|
||||
title = "LXQt Panel"
|
||||
description = "Geleneksel panel düzeni ile görev çubuğu, uygulama başlatıcı ve sistem tepsisi her zaman elinizin altında."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "file_manager"
|
||||
title = "PCManFM-Qt Dosya Yöneticisi"
|
||||
description = "Hafif ve hızlı PCManFM-Qt ile dosya işlemlerini kolayca yönetin. Sekmeli gezinme ve özelleştirilebilir arayüz sunar."
|
||||
|
||||
# ── LXDE ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "lxde"
|
||||
title = "PisiLinux LXDE"
|
||||
description = "Efsanevi hafif masaüstü LXDE. Çok düşük kaynak tüketimi ve güvenilir yapısıyla tanınır."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "lxde"
|
||||
title = "Openbox Tabanlı"
|
||||
description = "LXDE, Openbox pencere yöneticisini kullanır. İnce ayarlar ile akıcı bir deneyim sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "file_manager"
|
||||
title = "PCManFM Dosya Yöneticisi"
|
||||
description = "PCManFM, hızlı ve hafif yapısıyla dosya işlemlerinizi kolaylaştırır, ağaç görünümü ve sekme destekler."
|
||||
|
||||
# ── Lumina ────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "lumina"
|
||||
title = "PisiLinux Lumina"
|
||||
description = "Hafif ve bağımsız Lumina masa üstü. Qt tabanlı, BSD ve Linux sistemlerde düzgün çalışan minimal bir ortam."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "customization"
|
||||
title = "Tema Özelleştirme"
|
||||
description = "Lumina'nın tema sistemiyle renk şemaları ve arayüz stilini kolayca özelleştirin."
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [theme] – Arayüz renk şeması (Hex)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[theme]
|
||||
primary = "#1a73e8"
|
||||
accent = "#34a853"
|
||||
background = "#181824"
|
||||
text = "#e2e8f0"
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [oem] – Üretici (OEM) Kurulum Modu
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[oem]
|
||||
enabled = false
|
||||
skip_steps = []
|
||||
default_username = "oem"
|
||||
default_hostname = "pisi-oem"
|
||||
default_password = "oempisi-changeme"
|
||||
@@ -0,0 +1,339 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ Yali-RS Installation Tool — Visual Customization ║
|
||||
# ║ branding_en.toml ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [general] – Distribution Identity
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[general]
|
||||
# Sidebar logo (Yali)
|
||||
yali_logo = "assets/yali.png"
|
||||
|
||||
# Main page logo (PisiLinux distribution)
|
||||
pisi_logo_dark = "assets/pisi-logo-dark.png"
|
||||
pisi_logo_light = "assets/pisi-logo-light.png"
|
||||
|
||||
# Title of the installation window
|
||||
title = "PiSi Linux Installation"
|
||||
|
||||
# Subtitle displayed in the left sidebar
|
||||
subtitle = "YALI"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [slides] – Slides shown during installation
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[slides]
|
||||
|
||||
# Slide transition duration (seconds)
|
||||
interval_secs = 6
|
||||
|
||||
|
||||
# ── Slide Icons → File Path Mappings ─────────────────────────────
|
||||
[slides.icons]
|
||||
pisilogo = "assets/pisilinux-logo.png"
|
||||
pisi = "assets/pisi-software-center.png"
|
||||
community = "assets/community.png"
|
||||
pisi_speed = "assets/pisi_speed.png"
|
||||
securety = "assets/securety.png"
|
||||
customization = "assets/customization.png"
|
||||
|
||||
# Masaüstü İkonları
|
||||
budgie = "assets/budgie.png"
|
||||
budgie_applets = "assets/budgie_applets.png"
|
||||
budgie_raven = "assets/budgie_raven.png"
|
||||
budgie_gtk_theme = "assets/budgie_gtk_theme.png"
|
||||
|
||||
cinnamon = "assets/cinnamon.png"
|
||||
cinnamon_panel = "assets/cinnamon_panel.png"
|
||||
cinnamon_settings = "assets/cinnamon_settings.png"
|
||||
cinnamon_desklets = "assets/cinnamon_desklets.png"
|
||||
|
||||
gnome = "assets/gnome.png"
|
||||
gnome_search = "assets/gnome_search.png"
|
||||
gnome_extensions = "assets/gnome_extensions.png"
|
||||
|
||||
kde = "assets/kde.png"
|
||||
file_manager = "assets/file_manager.png"
|
||||
kde_connect = "assets/kde_connect.png"
|
||||
discover = "assets/discover.png"
|
||||
|
||||
lxde = "assets/lxde.png"
|
||||
lxde_openbox = "assets/lxde_openbox.png"
|
||||
lxde_lxpanel = "assets/lxde_lxpanel.png"
|
||||
|
||||
lxqt = "assets/lxqt.png"
|
||||
lxqt_panel = "assets/lxqt_panel.png"
|
||||
|
||||
lumina = "assets/lumina.png"
|
||||
lumina_applications = "assets/lumina_applications.png"
|
||||
lumina_theme = "assets/lumina_theme.png"
|
||||
lumina_panel = "assets/lumina_panel.png"
|
||||
|
||||
mate = "assets/mate.png"
|
||||
mate_settings = "assets/mate_settings.png"
|
||||
mate_applications = "assets/mate_applications.png"
|
||||
|
||||
xfce = "assets/xfce.png"
|
||||
xfce_panel = "assets/xfce_panel.png"
|
||||
xfce_settings = "assets/xfce_settings.png"
|
||||
|
||||
|
||||
# ── Common Slides ────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
icon = "pisilogo"
|
||||
title = "Welcome to Pisi GNU/Linux"
|
||||
description = "Pisi is a Turkish-supported GNU/Linux distribution that combines speed, stability, and ease of use."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisi"
|
||||
title = "PISI Package Manager"
|
||||
description = "Access thousands of packages with a single command. Install anything you need easily with `pisi install <package>`."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "community"
|
||||
title = "Community Support"
|
||||
description = "Our active community at forum.pisilinux.org is ready to answer your questions. Our wiki pages are always accessible."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisi_speed"
|
||||
title = "Speed & Performance"
|
||||
description = "Thanks to an optimized kernel and startup services, PisiLinux boots in seconds and uses minimal resources."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "securety"
|
||||
title = "Security First"
|
||||
description = "Keep your system secure with regular security updates, AppArmor profiles, and secure default settings."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "customization"
|
||||
title = "Customization"
|
||||
description = "Tailor everything to your taste — from the desktop environment and theme colors to panel layout and keyboard shortcuts."
|
||||
|
||||
# ── Budgie ────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie"
|
||||
title = "PisiLinux Budgie"
|
||||
description = "A modern, clean, and elegant Budgie desktop. Built on the GNOME stack and user-friendly."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_applets"
|
||||
title = "Budgie Desktop Applets"
|
||||
description = "Easily add tools like weather, system monitor, and calendar via Budgie's panel applets."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_raven"
|
||||
title = "Raven Notification Center"
|
||||
description = "Access volume, media controls, notifications, and quick settings from the Raven panel."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_gtk_theme"
|
||||
title = "GTK Theme Support"
|
||||
description = "Budgie runs GTK themes and GNOME applications seamlessly, ensuring visual consistency."
|
||||
|
||||
# ── Cinnamon ──────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon"
|
||||
title = "PisiLinux Cinnamon"
|
||||
description = "Cinnamon combines the traditional desktop experience with modern features, offering a powerful and flexible environment."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_panel"
|
||||
title = "Cinnamon Panel"
|
||||
description = "Customize your panel with applets, launchers, and system indicators for a classic yet powerful desktop."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_settings"
|
||||
title = "Settings Manager"
|
||||
description = "Fine-tune every aspect of your Cinnamon desktop through the comprehensive Settings Manager."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_desklets"
|
||||
title = "Cinnamon Desklets"
|
||||
description = "Keep notes, clocks, and system info always visible on your desktop with Cinnamon Desklets."
|
||||
|
||||
# ── GNOME ─────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome"
|
||||
title = "PisiLinux GNOME"
|
||||
description = "Reduce distractions and focus on your work with the clean and focused GNOME desktop environment."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome_search"
|
||||
title = "GNOME Search"
|
||||
description = "Press the Super key and start typing. Instantly reach applications, files, and settings."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome_extensions"
|
||||
title = "GNOME Extensions"
|
||||
description = "Shape your desktop to your needs with hundreds of extensions from extensions.gnome.org."
|
||||
|
||||
# ── KDE ───────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "kde"
|
||||
title = "PisiLinux KDE Plasma"
|
||||
description = "Meet the modern, customizable, and powerful KDE Plasma desktop. Everything is at your fingertips."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "file_manager"
|
||||
title = "Dolphin File Manager"
|
||||
description = "Dolphin makes managing your files easy with tabbed browsing, dual-panel view, and powerful search."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "kde_connect"
|
||||
title = "KDE Connect"
|
||||
description = "Connect your phone to your computer. Notifications, file transfer, and clipboard sharing — all with KDE Connect."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "discover"
|
||||
title = "Discover Software Center"
|
||||
description = "Easily find, install, and update applications from the visual interface with Discover."
|
||||
|
||||
# ── LXQt ──────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "lxqt"
|
||||
title = "PisiLinux LXQt"
|
||||
description = "A lightweight, fast, and modern LXQt desktop environment. Low resource consumption, high performance."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "lxqt_panel"
|
||||
title = "LXQt Panel"
|
||||
description = "The traditional panel layout puts the taskbar, application launcher, and system tray always within reach."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "file_manager"
|
||||
title = "PCManFM-Qt File Manager"
|
||||
description = "Manage files effortlessly with the lightweight and fast PCManFM-Qt. Tabbed navigation and a customizable interface."
|
||||
|
||||
# ── LXDE ──────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "lxde"
|
||||
title = "PisiLinux LXDE"
|
||||
description = "The legendary lightweight LXDE desktop. Known for extremely low resource usage and a reliable build."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "lxde_openbox"
|
||||
title = "Openbox-Based"
|
||||
description = "LXDE uses the Openbox window manager. Fine-tune it for a smooth and responsive experience."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "file_manager"
|
||||
title = "PCManFM File Manager"
|
||||
description = "PCManFM speeds up your file operations with its fast and lightweight build, supporting tree view and tabs."
|
||||
|
||||
# ── Lumina ────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "lumina"
|
||||
title = "PisiLinux Lumina"
|
||||
description = "A lightweight and independent Lumina desktop. Qt-based, designed to run cleanly on BSD and Linux systems."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "lumina_applications"
|
||||
title = "Application Support"
|
||||
description = "Lumina works well with core utilities and many popular Qt apps, providing a practical everyday experience."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "lumina_theme"
|
||||
title = "Theme Customization"
|
||||
description = "Easily customize color schemes and interface styles with Lumina's flexible theme system."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "lumina_panel"
|
||||
title = "Lumina Panel"
|
||||
description = "A clean panel with a taskbar, application launcher, and system tray keeps your desktop organized."
|
||||
|
||||
# ── MATE ──────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "mate"
|
||||
title = "PisiLinux MATE"
|
||||
description = "MATE for those who love the traditional desktop layout. Developed with GTK+ 3 for a modern and smooth experience."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "file_manager"
|
||||
title = "Caja File Manager"
|
||||
description = "Manage your files easily with MATE's powerful Caja. Dual panel, tabbed navigation, and rich features."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "mate_settings"
|
||||
title = "MATE Settings"
|
||||
description = "Customize your MATE desktop with comprehensive settings for appearance, display, keyboard, and more."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "mate_applications"
|
||||
title = "Rich Application Suite"
|
||||
description = "MATE comes with a rich set of classic applications — from text editors to image viewers, all well-integrated."
|
||||
|
||||
# ── XFCE ──────────────────────────────────────────────────────────
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce"
|
||||
title = "PisiLinux XFCE"
|
||||
description = "A lightweight, fast, and user-friendly XFCE desktop environment. Low resource consumption, high performance."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce_panel"
|
||||
title = "XFCE Panel"
|
||||
description = "The traditional panel layout puts the taskbar, application menu, and system tray always within reach."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "file_manager"
|
||||
title = "Thunar File Manager"
|
||||
description = "Manage your files easily with the fast and lightweight Thunar. Tree view, tabbed navigation, and customizable features."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce_settings"
|
||||
title = "Whisker Menu"
|
||||
description = "A modern alternative to the classic application menu. Find apps easily and organize your favorites with Whisker Menu."
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [theme] – UI Style & Color Palette
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[theme]
|
||||
primary = "#1a73e8"
|
||||
accent = "#34a853"
|
||||
background = "#181824"
|
||||
text = "#e2e8f0"
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [oem] – OEM Installer Configuration (Factory Mode)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[oem]
|
||||
enabled = false
|
||||
skip_steps = [0, 1, 2, 3, 4]
|
||||
default_username = "pisi"
|
||||
default_hostname = "pisi-pc"
|
||||
default_password = "pisi"
|
||||
@@ -0,0 +1,354 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ Yali-RS Kurulum Aracı — Görsel Özelleştirme ║
|
||||
# ║ branding.toml ║
|
||||
# ╠══════════════════════════════════════════════════════════════════╣
|
||||
# ║ Yali bu dosyayı sırasıyla şu yollardan arar: ║
|
||||
# ║ 1. /etc/yali/branding.toml ║
|
||||
# ║ 2. /usr/share/yali/branding.toml ║
|
||||
# ║ 3. Çalışma dizini altındaki "branding.toml" ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [general] – Dağıtım kimliği
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[general]
|
||||
# Sol kenar çubuğu için Yali logosu
|
||||
yali_logo = "assets/yali.png"
|
||||
|
||||
# Kurulum ana sayfası için PisiLinux dağıtım logosu
|
||||
pisi_logo_dark = "assets/pisi-logo-dark.png"
|
||||
pisi_logo_light = "assets/pisi-logo-light.png"
|
||||
|
||||
# Kurulum penceresinin başlığı (pencere çubuğu)
|
||||
title = "PiSi Linux Kurulumu"
|
||||
|
||||
# Sol kenar çubuğunda görüntülenen dağıtım ismi
|
||||
subtitle = "YALI"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [slides] – Kurulum sırasında gösterilen slaytlar
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[slides]
|
||||
|
||||
# Slayt geçiş süresi (saniye)
|
||||
interval_secs = 6
|
||||
|
||||
|
||||
# ── Slayt ikonları → görsel dosya yolu eşlemesi ──────────────────
|
||||
# Geliştirici notu: Yeni ikon eklemek için sadece buraya satır ekle.
|
||||
[slides.icons]
|
||||
pisilogo = "assets/pisilinux-logo.png"
|
||||
pisi = "assets/pisi-software-center.png"
|
||||
community = "assets/community.png"
|
||||
pisi_speed = "assets/pisi_speed.png"
|
||||
securety = "assets/securety.png"
|
||||
customization = "assets/customization.png"
|
||||
|
||||
budgie = "assets/budgie.png"
|
||||
budgie_applets = "assets/budgie_applets.png"
|
||||
budgie_raven = "assets/budgie_raven.png"
|
||||
budgie_gtk_theme = "assets/budgie_gtk_theme.png"
|
||||
|
||||
cinnamon = "assets/cinnamon.png"
|
||||
cinnamon_panel = "assets/cinnamon_panel.png"
|
||||
cinnamon_settings = "assets/cinnamon_settings.png"
|
||||
cinnamon_desklets = "assets/cinnamon_desklets.png"
|
||||
|
||||
gnome = "assets/gnome.png"
|
||||
gnome_search = "assets/gnome_search.png"
|
||||
gnome_extensions = "assets/gnome_extensions.png"
|
||||
|
||||
kde = "assets/kde.png"
|
||||
kde_connect = "assets/kde_connect.png"
|
||||
discover = "assets/discover.png"
|
||||
file_manager = "assets/file_manager.png"
|
||||
|
||||
lxde = "assets/lxde.png"
|
||||
lxqt = "assets/lxqt.png"
|
||||
lumina = "assets/lumina.png"
|
||||
|
||||
mate = "assets/mate.png"
|
||||
mate_settings = "assets/mate_settings.png"
|
||||
|
||||
xfce = "assets/xfce.png"
|
||||
xfce_settings = "assets/xfce_settings.png"
|
||||
xfce_panel = "assets/xfce_panel.png"
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
# [[slides.items]] – Slayt içerikleri
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# Her [[slides.items]] bloğu bir slaytı tanımlar.
|
||||
#
|
||||
# Alanlar:
|
||||
# icon = Görsel için yukarıdaki [slides.icons] anahtarı
|
||||
# title = Slayt başlığı
|
||||
# description = Slayt açıklama metni
|
||||
# desktop = (isteğe bağlı) Yalnızca belirli masaüstünde göster.
|
||||
# Boş bırakılırsa tüm masaüstlerinde gösterilir.
|
||||
# Değerler: "xfce", "kde", "gnome", "mate", "budgie",
|
||||
# "cinnamon", "lxde", "lxqt", "lumina"
|
||||
#
|
||||
# Geliştirici notu:
|
||||
# Yeni bir slayt eklemek veya metni değiştirmek için yalnızca
|
||||
# buraya [[slides.items]] bloğu ekleyin / düzenleyin.
|
||||
# Rust koduna dokunmanıza gerek yoktur.
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
|
||||
# ── Tüm masaüstlerinde gösterilen ortak slaytlar ──────────────────
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisilogo"
|
||||
title = "Pisi GNU/Linux'a Hoş Geldiniz"
|
||||
description = "Pisi; hız, kararlılık ve kullanım kolaylığını bir araya getiren Türkçe destekli bir GNU/Linux dağıtımıdır."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisi"
|
||||
title = "PISI Paket Yöneticisi"
|
||||
description = "Binlerce pakete tek komutla erişin. `pisi install <paket>` ile ihtiyacınız olan her şeyi kolayca kurabilirsiniz."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "community"
|
||||
title = "Topluluk Desteği"
|
||||
description = "forum.pisilinux.org adresindeki aktif topluluğumuz sorularınızı yanıtlamak için hazır. Wiki sayfalarımız da her an erişilebilir."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "pisi_speed"
|
||||
title = "Hız ve Performans"
|
||||
description = "Optimize edilmiş çekirdek ve başlangıç servisleri sayesinde PisiLinux saniyeler içinde açılır ve minimum kaynak kullanır."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "securety"
|
||||
title = "Güvenlik Önce Gelir"
|
||||
description = "Düzenli güvenlik güncellemeleri, AppArmor profilleri ve güvenli varsayılan ayarlarla sisteminizi koruyun."
|
||||
|
||||
[[slides.items]]
|
||||
icon = "customization"
|
||||
title = "Özelleştirme"
|
||||
description = "Masaüstü ortamından tema renklerine, panel düzeninden klavye kısayollarına kadar her şeyi zevkinize göre ayarlayın."
|
||||
|
||||
# ── XFCE ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce"
|
||||
title = "PisiLinux XFCE"
|
||||
description = "Hafif, hızlı ve kullanıcı dostu XFCE masaüstü ortamı. Kaynak tüketimi düşük, performansı yüksektir."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce_panel"
|
||||
title = "XFCE Panel"
|
||||
description = "Geleneksel panel düzeni ile görev çubuğu, uygulama menüsü ve sistem tepsisi her zaman elinizin altında."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "file_manager"
|
||||
title = "Thunar Dosya Yöneticisi"
|
||||
description = "Hızlı ve hafif Thunar ile dosya işlemlerinizi kolayca yapın. Ağaç görünümü, sekmeli gezinme ve özelleştirilebilir özellikler sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "xfce"
|
||||
icon = "xfce_settings"
|
||||
title = "Ayarlar Merkezi"
|
||||
description = "Klasik uygulama menüsüne modern bir alternatif. Whisker Menu ile uygulamaları kolayca bulun, favorilerinizi düzenleyin."
|
||||
|
||||
# ── KDE Plasma ────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "kde"
|
||||
title = "PisiLinux KDE Plasma"
|
||||
description = "Modern, özelleştirilebilir ve güçlü KDE Plasma masaüstü ortamıyla tanışın. Her şey elinizin altında."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "file_manager"
|
||||
title = "Dolphin Dosya Yöneticisi"
|
||||
description = "Sekmeli gezinme, ikili panel ve güçlü arama özelliğiyle Dolphin dosyalarınızı yönetmeyi kolaylaştırır."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "kde_connect"
|
||||
title = "KDE Bağlan"
|
||||
description = "Telefonunuzu bilgisayarınıza bağlayın. Bildirimler, dosya aktarımı ve klipboard paylaşımı KDE Connect ile mümkün."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "kde"
|
||||
icon = "discover"
|
||||
title = "Discover Yazılım Merkezi"
|
||||
description = "Discover ile uygulamaları görsel arayüzden kolayca bulun, kurun ve güncelleyin."
|
||||
|
||||
# ── GNOME ─────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome"
|
||||
title = "PisiLinux GNOME"
|
||||
description = "Sade ve odaklı GNOME masaüstü ortamı ile dikkat dağıtıcı unsurları azaltın, işinize konsantre olun."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome_search"
|
||||
title = "GNOME Arama"
|
||||
description = "Super tuşuna basıp yazmaya başlayın. Uygulama, dosya ve ayarlara anında ulaşın."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "gnome"
|
||||
icon = "gnome_extensions"
|
||||
title = "GNOME Eklentileri"
|
||||
description = "extensions.gnome.org adresinden yüzlerce eklentiyle masaüstünüzü ihtiyaçlarınıza göre şekillendirin."
|
||||
|
||||
# ── MATE ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "mate"
|
||||
title = "PisiLinux MATE"
|
||||
description = "Geleneksel masaüstü düzenini sevenler için MATE. GTK+ 3 ile geliştirilmiş, modern ve akıcı bir deneyim sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "file_manager"
|
||||
title = "Caja Dosya Yöneticisi"
|
||||
description = "MATE'in güçlü dosya yöneticisi Caja ile dosya işlemlerinizi kolayca yapın. Çift panel, sekmeli gezinme ve geniş özellikler sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "mate_settings"
|
||||
title = "MATE Ayarları"
|
||||
description = "Görünüm, ekran, klavye ve daha fazlası için kapsamlı ayarlarla MATE masaüstünüzü özelleştirin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "mate"
|
||||
icon = "customization"
|
||||
title = "Zengin Uygulama Paketi"
|
||||
description = "MATE; metin editöründen görüntü görüntüleme yazılımına kadar geniş, iyi entegre edilmiş klasik uygulamalar sunar."
|
||||
|
||||
# ── Budgie ────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie"
|
||||
title = "PisiLinux Budgie"
|
||||
description = "Modern, sade ve şık Budgie masaüstü. GNOME altyapısı üzerine inşa edilmiş, kullanıcı dostudur."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_applets"
|
||||
title = "Budgie Desktop Applets"
|
||||
description = "Budgie'nin panel appletleri sayesinde hava durumu, sistem izleyici, takvim gibi araçları kolayca ekleyin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_raven"
|
||||
title = "Raven Bildirim Merkezi"
|
||||
description = "Raven panelinden ses seviyesi, medya kontrolleri, bildirimler ve hızlı ayarlara erişin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "budgie"
|
||||
icon = "budgie_gtk_theme"
|
||||
title = "GTK Tema Desteği"
|
||||
description = "Budgie, GTK temalarını ve GNOME uygulamalarını sorunsuz çalıştırır, görsel bütünlük sağlar."
|
||||
|
||||
# ── Cinnamon ──────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon"
|
||||
title = "PisiLinux Cinnamon"
|
||||
description = "Geleneksel masaüstü deneyimini modern özelliklerle birleştiren Cinnamon, güçlü ve esnek bir ortam sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_panel"
|
||||
title = "Cinnamon Paneli"
|
||||
description = "Panelinizi applet'ler, başlatıcılar ve sistem göstergeleriyle özelleştirin; klasik ama güçlü bir masaüstü deneyimi yaşayın."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_settings"
|
||||
title = "Ayarlar Yöneticisi"
|
||||
description = "Cinnamon'un kapsamlı Ayarlar Yöneticisi aracılığıyla masaüstünüzün her yönünü özelleştirin."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "cinnamon"
|
||||
icon = "cinnamon_desklets"
|
||||
title = "Cinnamon Desklets"
|
||||
description = "Masaüstü widget'ları ile notlar, saatler ve sistem bilgileri her zaman görünür kalsın."
|
||||
|
||||
# ── LXQt ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "lxqt"
|
||||
title = "PisiLinux LXQt"
|
||||
description = "Hafif, hızlı ve modern LXQt masaüstü ortamı. Kaynak tüketimi düşük, performansı yüksektir."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "file_manager"
|
||||
title = "LXQt Panel"
|
||||
description = "Geleneksel panel düzeni ile görev çubuğu, uygulama başlatıcı ve sistem tepsisi her zaman elinizin altında."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxqt"
|
||||
icon = "file_manager"
|
||||
title = "PCManFM-Qt Dosya Yöneticisi"
|
||||
description = "Hafif ve hızlı PCManFM-Qt ile dosya işlemlerini kolayca yönetin. Sekmeli gezinme ve özelleştirilebilir arayüz sunar."
|
||||
|
||||
# ── LXDE ──────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "lxde"
|
||||
title = "PisiLinux LXDE"
|
||||
description = "Efsanevi hafif masaüstü LXDE. Çok düşük kaynak tüketimi ve güvenilir yapısıyla tanınır."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "lxde"
|
||||
title = "Openbox Tabanlı"
|
||||
description = "LXDE, Openbox pencere yöneticisini kullanır. İnce ayarlar ile akıcı bir deneyim sunar."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lxde"
|
||||
icon = "file_manager"
|
||||
title = "PCManFM Dosya Yöneticisi"
|
||||
description = "PCManFM, hızlı ve hafif yapısıyla dosya işlemlerinizi kolaylaştırır, ağaç görünümü ve sekme destekler."
|
||||
|
||||
# ── Lumina ────────────────────────────────────────────────────────
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "lumina"
|
||||
title = "PisiLinux Lumina"
|
||||
description = "Hafif ve bağımsız Lumina masa üstü. Qt tabanlı, BSD ve Linux sistemlerde düzgün çalışan minimal bir ortam."
|
||||
|
||||
[[slides.items]]
|
||||
desktop = "lumina"
|
||||
icon = "customization"
|
||||
title = "Tema Özelleştirme"
|
||||
description = "Lumina'nın tema sistemiyle renk şemaları ve arayüz stilini kolayca özelleştirin."
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [theme] – Arayüz renk şeması (Hex)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[theme]
|
||||
primary = "#1a73e8"
|
||||
accent = "#34a853"
|
||||
background = "#181824"
|
||||
text = "#e2e8f0"
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# [oem] – Üretici (OEM) Kurulum Modu
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
[oem]
|
||||
enabled = false
|
||||
skip_steps = []
|
||||
default_username = "oem"
|
||||
default_hostname = "pisi-oem"
|
||||
default_password = "oempisi-changeme"
|
||||
+295
-104
@@ -8,8 +8,11 @@ confirm = "Confirm"
|
||||
# ── Welcome ───────────────────────────────────────────────
|
||||
welcome = "Welcome"
|
||||
welcome_title = "Welcome to YALI Installation Tool"
|
||||
welcome_description = "This tool will guide you through the installation process."
|
||||
welcome_description = "This tool will guide you through the installation process. Information about the operating system to be installed on your system:"
|
||||
select_language = "Select Language:"
|
||||
os = "OS"
|
||||
desktop = "Desktop"
|
||||
version = "Version"
|
||||
|
||||
# ── Location ──────────────────────────────────────────────
|
||||
location = "Location"
|
||||
@@ -72,108 +75,6 @@ execution_description = "Please wait. This may take a few minutes."
|
||||
start_install = "Start Installation"
|
||||
install_starting = "Starting installation…"
|
||||
|
||||
# ── Slides for PISILINUX ────────────────────────────────────────────
|
||||
welcome_slide_title = "Welcome to Pisi GNU/Linux"
|
||||
welcome_slide_description = "Pisi is a Turkish-supported GNU/Linux distribution that combines speed, stability, and ease of use."
|
||||
package_manager_title = "PISI Package Manager"
|
||||
package_manager_description = "Access thousands of packages with a single command. Install anything you need easily with `pisi install <package>`."
|
||||
community_title = "Community Support"
|
||||
community_description = "Our active community at forum.pisilinux.org is ready to answer your questions. Our wiki pages are always accessible."
|
||||
speed_title = "Speed & Performance"
|
||||
speed_description = "Thanks to an optimized kernel and startup services, PisiLinux boots in seconds and uses minimal resources."
|
||||
security_title = "Security First"
|
||||
security_description = "Keep your system secure with regular security updates, AppArmor profiles, and secure default settings."
|
||||
customization_title = "Customization"
|
||||
customization_description = "Tailor everything to your taste — from the desktop environment and theme colors to panel layout and keyboard shortcuts."
|
||||
|
||||
# ── Slides for BUDGIE ────────────────────────────────────────────
|
||||
budgie_title = "PisiLinux Budgie"
|
||||
budgie_description = "A modern, clean, and elegant Budgie desktop. Built on the GNOME stack and user-friendly."
|
||||
budgie_applets_title = "Budgie Desktop Applets"
|
||||
budgie_applets_description = "Easily add tools like weather, system monitor, and calendar via Budgie's panel applets."
|
||||
budgie_raven_title = "Raven Notification Center"
|
||||
budgie_raven_description = "Access volume, media controls, notifications, and quick settings from the Raven panel."
|
||||
budgie_gtk_theme_title = "GTK Theme Support"
|
||||
budgie_gtk_theme_description = "Budgie runs GTK themes and GNOME applications seamlessly, ensuring visual consistency."
|
||||
|
||||
# ── Slides for CINNAMON ────────────────────────────────────────────
|
||||
cinnamon_title = "PisiLinux Cinnamon"
|
||||
cinnamon_description = "Cinnamon combines the traditional desktop experience with modern features, offering a powerful and flexible environment."
|
||||
cinnamon_panel_title = "Cinnamon Panel"
|
||||
cinnamon_panel_description = "Customize your panel with applets, launchers, and system indicators for a classic yet powerful desktop."
|
||||
cinnamon_settings_title = "Settings Manager"
|
||||
cinnamon_settings_description = "Fine-tune every aspect of your Cinnamon desktop through the comprehensive Settings Manager."
|
||||
cinnamon_desklets_title = "Cinnamon Desklets"
|
||||
cinnamon_desklets_description = "Keep notes, clocks, and system info always visible on your desktop with Cinnamon Desklets."
|
||||
|
||||
# ── Slides for GNOME ────────────────────────────────────────────
|
||||
gnome_title = "PisiLinux GNOME"
|
||||
gnome_description = "Reduce distractions and focus on your work with the clean and focused GNOME desktop environment."
|
||||
gnome_search_title = "GNOME Search"
|
||||
gnome_search_description = "Press the Super key and start typing. Instantly reach applications, files, and settings."
|
||||
gnome_extensions_title = "GNOME Extensions"
|
||||
gnome_extensions_description = "Shape your desktop to your needs with hundreds of extensions from extensions.gnome.org."
|
||||
|
||||
# ── Slides for KDE/Plasma ────────────────────────────────────────────
|
||||
kde_title = "PisiLinux KDE Plasma"
|
||||
kde_description = "Meet the modern, customizable, and powerful KDE Plasma desktop. Everything is at your fingertips."
|
||||
dolphin_title = "Dolphin File Manager"
|
||||
dolphin_description = "Dolphin makes managing your files easy with tabbed browsing, dual-panel view, and powerful search."
|
||||
kde_connect_title = "KDE Connect"
|
||||
kde_connect_description = "Connect your phone to your computer. Notifications, file transfer, and clipboard sharing — all with KDE Connect."
|
||||
discover_title = "Discover Software Center"
|
||||
discover_description = "Easily find, install, and update applications from the visual interface with Discover."
|
||||
|
||||
# ── Slides for LXQt ────────────────────────────────────────────
|
||||
lxqt_title = "PisiLinux LXQt"
|
||||
lxqt_description = "A lightweight, fast, and modern LXQt desktop environment. Low resource consumption, high performance."
|
||||
lxqt_panel_title = "LXQt Panel"
|
||||
lxqt_panel_description = "The traditional panel layout puts the taskbar, application launcher, and system tray always within reach."
|
||||
lxqt_pcmanfm_qt_title = "PCManFM-Qt File Manager"
|
||||
lxqt_pcmanfm_qt_description = "Manage files effortlessly with the lightweight and fast PCManFM-Qt. Tabbed navigation and a customizable interface."
|
||||
lxqt_speed_title = "LXQt Speed"
|
||||
lxqt_speed_description = "LXQt is engineered for speed. Boot faster, respond quicker, and make the most of even older hardware."
|
||||
|
||||
# ── Slides for LXDE ────────────────────────────────────────────
|
||||
lxde_title = "PisiLinux LXDE"
|
||||
lxde_description = "The legendary lightweight LXDE desktop. Known for extremely low resource usage and a reliable build."
|
||||
lxde_openbox_title = "Openbox-Based"
|
||||
lxde_openbox_description = "LXDE uses the Openbox window manager. Fine-tune it for a smooth and responsive experience."
|
||||
lxde_pcmanfm_title = "PCManFM File Manager"
|
||||
lxde_pcmanfm_description = "PCManFM speeds up your file operations with its fast and lightweight build, supporting tree view and tabs."
|
||||
lxde_lxpanel_title = "LXPanel"
|
||||
lxde_lxpanel_description = "LXPanel provides a taskbar, application menu, and system tray in a classic desktop layout."
|
||||
|
||||
# ── Slides for LUMINA ────────────────────────────────────────────
|
||||
lumina_title = "PisiLinux Lumina"
|
||||
lumina_description = "A lightweight and independent Lumina desktop. Qt-based, designed to run cleanly on BSD and Linux systems."
|
||||
lumina_applications_title = "Application Support"
|
||||
lumina_applications_description = "Lumina works well with core utilities and many popular Qt apps, providing a practical everyday experience."
|
||||
lumina_theme_title = "Theme Customization"
|
||||
lumina_theme_description = "Easily customize color schemes and interface styles with Lumina's flexible theme system."
|
||||
lumina_panel_title = "Lumina Panel"
|
||||
lumina_panel_description = "A clean panel with a taskbar, application launcher, and system tray keeps your desktop organized."
|
||||
|
||||
# ── Slides for MATE ────────────────────────────────────────────
|
||||
mate_title = "PisiLinux MATE"
|
||||
mate_description = "MATE for those who love the traditional desktop layout. Developed with GTK+ 3 for a modern and smooth experience."
|
||||
mate_caja_title = "Caja File Manager"
|
||||
mate_caja_description = "Manage your files easily with MATE's powerful Caja. Dual panel, tabbed navigation, and rich features."
|
||||
mate_settings_title = "MATE Settings"
|
||||
mate_settings_description = "Customize your MATE desktop with comprehensive settings for appearance, display, keyboard, and more."
|
||||
mate_applications_title = "Rich Application Suite"
|
||||
mate_applications_description = "MATE comes with a rich set of classic applications — from text editors to image viewers, all well-integrated."
|
||||
|
||||
# ── Slides for XFCE ────────────────────────────────────────────
|
||||
xfce_title = "PisiLinux XFCE"
|
||||
xfce_description = "A lightweight, fast, and user-friendly XFCE desktop environment. Low resource consumption, high performance."
|
||||
xfce_panel_title = "XFCE Panel"
|
||||
xfce_panel_description = "The traditional panel layout puts the taskbar, application menu, and system tray always within reach."
|
||||
xfce_thunar_title = "Thunar File Manager"
|
||||
xfce_thunar_description = "Manage your files easily with the fast and lightweight Thunar. Tree view, tabbed navigation, and customizable features."
|
||||
xfce_settings_title = "Settings Manager"
|
||||
xfce_settings_description = "A modern alternative to the classic application menu. Find apps easily and organize your favorites with Whisker Menu."
|
||||
|
||||
|
||||
# ── Finish ────────────────────────────────────────────────
|
||||
finish = "Finished"
|
||||
@@ -200,11 +101,34 @@ partition_table_type = "Partition table"
|
||||
disk_too_small = "Disk too small"
|
||||
summary_partition_plan = "Partitioning"
|
||||
summary_custom_partitions = "Manual Partitions"
|
||||
summary_bootloader = "Bootloader"
|
||||
summary_datetime = "Date & Time"
|
||||
summary_ntp_enabled = "NTP enabled (auto)"
|
||||
summary_root = "Root"
|
||||
summary_root_enabled = "Password set"
|
||||
summary_root_disabled = "Disabled (locked)"
|
||||
summary_software = "Software"
|
||||
summary_display_manager = "Display Manager"
|
||||
summary_autologin = "Autologin"
|
||||
summary_autologin_user = "Autologin User"
|
||||
summary_desktop = "Desktop"
|
||||
|
||||
# ── Display Manager ───────────────────────────────
|
||||
display_manager = "Display Manager"
|
||||
display_manager_title = "Display Manager Configuration"
|
||||
display_manager_description = "Select your display manager and desktop environment."
|
||||
display_manager_select = "Display manager:"
|
||||
display_manager_de = "Desktop environment:"
|
||||
display_manager_autologin = "Automatic login"
|
||||
display_manager_autologin_user = "Autologin user:"
|
||||
display_manager_autologin_hint = "(first user)"
|
||||
display_manager_de_not_found = "(not detected)"
|
||||
display_manager_note = "Note: The display manager will be enabled by default on the installed system."
|
||||
mp_size_remaining = "Remaining Space"
|
||||
|
||||
# ── UI / General ──────────────────────────────────────────
|
||||
installer = "YALI Installation Tool"
|
||||
os_name = "PiSi GNU/LINUX"
|
||||
app_name = "YALI"
|
||||
|
||||
# ── Error screen ──────────────────────────────────────────
|
||||
error_show_log = "▼ Show Log Details"
|
||||
@@ -227,6 +151,7 @@ pwd_weak = "Weak"
|
||||
pwd_medium = "Medium"
|
||||
pwd_strong = "Strong"
|
||||
pwd_very_strong = "Very strong"
|
||||
use_same_for_admin = "Use the same password for the administrator (root) account"
|
||||
|
||||
# ── Checker ───────────────────────────────────────────────
|
||||
check_disk_space = "Disk Space"
|
||||
@@ -256,8 +181,13 @@ job_fstab = "Generating fstab"
|
||||
job_hostname = "Configuring hostname"
|
||||
job_locale = "Configuring locale"
|
||||
job_timezone = "Setting timezone"
|
||||
job_datetime = "Configuring date & time"
|
||||
job_keyboard = "Configuring keyboard layout"
|
||||
job_user = "Creating user account"
|
||||
job_install_packages = "Installing selected packages"
|
||||
job_ldconfig = "Configuring shared libraries (ldconfig)"
|
||||
job_update_env = "Updating system environment"
|
||||
job_cleanup_live = "Cleaning up live environment traces"
|
||||
|
||||
# ── Manual Partition UI ────────────────────────────────────
|
||||
manual_partition_title = "Manual Partitioning"
|
||||
@@ -324,8 +254,269 @@ mp_delete_confirm_yes = "✓ Yes, Delete"
|
||||
plan_root_suffix = " (root)"
|
||||
disk_min_required = " ↳ %{err} (min. %{n} GB required)"
|
||||
|
||||
|
||||
error_partition_plan_not_found = "Partition plan not found."
|
||||
|
||||
# ── License ───────────────────────────────────────────────
|
||||
license = "License"
|
||||
license_title = "GNU General Public License"
|
||||
license_description = "Please read and accept the license terms to continue."
|
||||
license_accept = "I have read and accept the terms of the GNU General Public License."
|
||||
|
||||
# ── Admin (root) ───────────────────────────────────────────
|
||||
admin = "Admin"
|
||||
admin_title = "Root Password"
|
||||
admin_description = "Set a password for the root (administrator) account. Leave empty to disable direct root login."
|
||||
admin_password_label = "Root password:"
|
||||
admin_password_confirm_label = "Confirm root password:"
|
||||
admin_password_short = "Root password must be at least 4 characters."
|
||||
|
||||
# ── Date/Time ──────────────────────────────────────────────
|
||||
datetime = "Date & Time"
|
||||
datetime_title = "Date & Time Settings"
|
||||
datetime_description = "Configure the system date and time."
|
||||
datetime_ntp_label = "Network Time (NTP):"
|
||||
datetime_ntp_on = "Enabled — time syncs automatically"
|
||||
datetime_ntp_off = "Disabled — set manually"
|
||||
datetime_date_label = "Date:"
|
||||
datetime_time_label = "Time:"
|
||||
datetime_year = "Year:"
|
||||
datetime_month = "Month:"
|
||||
datetime_day = "Day:"
|
||||
datetime_ntp_info = "NTP will synchronize the system clock over the network after installation."
|
||||
datetime_manual_info = "Set the date and time manually. The system will use these values."
|
||||
|
||||
# ── Network ────────────────────────────────────────────────
|
||||
network = "Network"
|
||||
network_title = "Network Configuration"
|
||||
network_description = "Configure network connections and proxy settings."
|
||||
network_connected = "Connected:"
|
||||
network_disconnected = "Disconnected"
|
||||
network_scan = "🔍 Scan Wi-Fi Networks"
|
||||
network_rescan = "🔄 Rescan"
|
||||
network_scan_count = "Networks found:"
|
||||
network_connect = "Connect"
|
||||
network_password_hint = "Password"
|
||||
network_proxy_label = "Configure proxy:"
|
||||
|
||||
# ── Software ───────────────────────────────────────────────
|
||||
software = "Software"
|
||||
software_title = "Software Selection"
|
||||
software_description = "Choose which software to install."
|
||||
software_desktops = "Desktop Environments"
|
||||
software_desktop_xfce = "XFCE — Lightweight and fast"
|
||||
software_desktop_kde = "KDE Plasma — Modern and feature-rich"
|
||||
software_desktop_gnome = "GNOME — Clean and focused"
|
||||
software_desktop_cinnamon = "Cinnamon — Traditional and powerful"
|
||||
software_additional = "Additional Collections"
|
||||
software_office = "Office — LibreOffice, document tools"
|
||||
software_development = "Development — GCC, Git, IDE tools"
|
||||
software_multimedia = "Multimedia — Codecs, players, editors"
|
||||
software_minimal = "⚠ Minimal — only base system (overrides others)"
|
||||
software_minimal_warning = "Selected 'Minimal' will override all other choices. Only essential packages will be installed."
|
||||
|
||||
# ── Bootloader ─────────────────────────────────────────────
|
||||
bootloader = "Bootloader"
|
||||
bootloader_title = "Bootloader Configuration"
|
||||
bootloader_description = "Configure the bootloader (GRUB) settings."
|
||||
bootloader_device_label = "Install to device:"
|
||||
bootloader_device_hint = "(default: target disk)"
|
||||
bootloader_timeout_label = "Timeout:"
|
||||
bootloader_timeout_suffix = "seconds"
|
||||
bootloader_password_label = "GRUB password (optional):"
|
||||
bootloader_kernel_label = "Kernel parameters:"
|
||||
bootloader_kernel_hint = "(e.g. quiet splash)"
|
||||
rescue = "Rescue"
|
||||
rescue_button = "🆘 Rescue Mode"
|
||||
rescue_title = "Rescue Mode"
|
||||
rescue_description = "Repair an existing PisiLinux installation."
|
||||
rescue_no_installations = "No Linux partitions found. Please check the system and try again."
|
||||
rescue_scan = "🔍 Scan"
|
||||
rescue_detected = "Detected Linux Partitions:"
|
||||
rescue_chroot = "📂 Rescue Shell (chroot)"
|
||||
rescue_chroot_start = "Starting chroot shell…"
|
||||
rescue_grub = "🔧 Reinstall GRUB"
|
||||
rescue_grub_start = "Reinstalling GRUB…"
|
||||
rescue_return = "↩ Return to Normal Installer"
|
||||
rescue_not_available = "Rescue mode: no existing Linux installation found."
|
||||
rescue_pisi_history = "📜 Pisi History Rollback"
|
||||
rescue_pisi_history_title = "Pisi Package History"
|
||||
rescue_pisi_history_desc = "Select a history entry and click Rollback to revert to that state."
|
||||
rescue_pisi_history_scan = "🔍 List History"
|
||||
rescue_pisi_history_empty = "No package history found or could not be read."
|
||||
rescue_pisi_takeback = "↩ Rollback to This Point"
|
||||
rescue_pisi_takeback_start = "Running pisi takeback…"
|
||||
rescue_pisi_history_ok = "Rollback completed successfully."
|
||||
rescue_pisi_history_err = "Error: %{err}"
|
||||
|
||||
# ── LUKS ──────────────────────────────────────────────────
|
||||
luks_enable_root = "Encrypt root partition (LUKS)"
|
||||
luks_password = "Encryption password:"
|
||||
luks_password_weak = "Password is too short (minimum 4 characters)"
|
||||
|
||||
error_target_disk_not_selected = "No target disk selected."
|
||||
error_thread_terminated = "Install thread terminated unexpectedly."
|
||||
error_thread_unexpectedly_terminated = "Install thread terminated unexpectedly."
|
||||
|
||||
# ── Netinstall ─────────────────────────────────────────
|
||||
netinstall = "Software Selection"
|
||||
netinstall_title = "Extra Software"
|
||||
netinstall_description = "Select additional package groups to install."
|
||||
netinstall_package_count = "packages"
|
||||
netinstall_selected = "selected"
|
||||
|
||||
# ── Media Check ──────────────────────────────────────────────
|
||||
media_check = "Media Check"
|
||||
media_check_title = "Verify Installation Media"
|
||||
media_check_description = "Check the integrity of your ISO or USB drive."
|
||||
media_check_scan = "🔍 Scan Media"
|
||||
media_check_select = "Select file to verify:"
|
||||
media_check_running = "Checking… please wait."
|
||||
media_check_ok = "✅ Media integrity verified successfully."
|
||||
media_check_fail = "❌ Media integrity check FAILED! Please re-download."
|
||||
media_check_no_md5 = "⚠️ md5sum or sha256sum tools not found."
|
||||
media_check_file_not_found = "⚠️ Selected file not found."
|
||||
media_check_path_label = "File path:"
|
||||
media_check_path_hint = "e.g. /run/live/medium/pisilinux.iso"
|
||||
media_check_algorithm = "Algorithm:"
|
||||
job_media_check = "Verifying installation media"
|
||||
|
||||
# ── CLI / Auto-install ─────────────────────────────────────
|
||||
hostname = "Hostname"
|
||||
timezone = "Timezone"
|
||||
username = "Username"
|
||||
|
||||
# ── Slideshow (fallback) ───────────────────────────────────
|
||||
welcome_slide_title = "Welcome to Pisi Linux"
|
||||
welcome_slide_description = "A modern, fast, and secure GNU/Linux distribution."
|
||||
|
||||
package_manager_title = "Pisi Package Manager"
|
||||
package_manager_description = "A powerful package manager with dependency resolution, history rollback, and atomic updates."
|
||||
|
||||
community_title = "Community Driven"
|
||||
community_description = "Built by the community for the community. Pisi Linux is free and open source."
|
||||
|
||||
speed_title = "Optimized for Speed"
|
||||
speed_description = "Designed to run fast on both modern and older hardware."
|
||||
|
||||
security_title = "Security First"
|
||||
security_description = "Regular security updates and a robust permission system keep your system safe."
|
||||
|
||||
customization_title = "Full Customization"
|
||||
customization_description = "Choose your desktop, applications, and look & feel during installation."
|
||||
|
||||
budgie_title = "Budgie Desktop"
|
||||
budgie_description = "A modern, elegant desktop environment designed with simplicity in mind."
|
||||
|
||||
budgie_applets_title = "Budgie Applets"
|
||||
budgie_applets_description = "Customizable applets for notifications, system tray, and more."
|
||||
|
||||
budgie_raven_title = "Budgie Raven"
|
||||
budgie_raven_description = "Notification center and settings panel for quick access."
|
||||
|
||||
budgie_gtk_theme_title = "GTK Theme Integration"
|
||||
budgie_gtk_theme_description = "Seamless GTK theme support for consistent application appearance."
|
||||
|
||||
cinnamon_title = "Cinnamon Desktop"
|
||||
cinnamon_description = "A traditional desktop layout with modern features."
|
||||
|
||||
cinnamon_panel_title = "Cinnamon Panel"
|
||||
cinnamon_panel_description = "Flexible panel system with applets, launchers, and tray icons."
|
||||
|
||||
cinnamon_settings_title = "Cinnamon Settings"
|
||||
cinnamon_settings_description = "Comprehensive system settings accessible from the menu."
|
||||
|
||||
cinnamon_desklets_title = "Cinnamon Desklets"
|
||||
cinnamon_desklets_description = "Interactive desklets for weather, clock, system monitoring and more."
|
||||
|
||||
gnome_title = "GNOME Desktop"
|
||||
gnome_description = "A clean, distraction-free desktop environment."
|
||||
|
||||
gnome_search_title = "GNOME Search"
|
||||
gnome_search_description = "Instant search across applications, files, and settings."
|
||||
|
||||
gnome_extensions_title = "GNOME Extensions"
|
||||
gnome_extensions_description = "Extend your desktop with community-built extensions."
|
||||
|
||||
kde_title = "KDE Plasma Desktop"
|
||||
kde_description = "Feature-rich, highly customizable desktop environment."
|
||||
|
||||
dolphin_title = "Dolphin File Manager"
|
||||
dolphin_description = "Intuitive file manager with split-pane view and powerful search."
|
||||
|
||||
kde_connect_title = "KDE Connect"
|
||||
kde_connect_description = "Seamlessly integrate your phone with your desktop."
|
||||
|
||||
discover_title = "Discover Software Center"
|
||||
discover_description = "Browse and install applications with a single click."
|
||||
|
||||
lxde_title = "LXDE Desktop"
|
||||
lxde_description = "Lightweight desktop environment for older hardware."
|
||||
|
||||
lxde_openbox_title = "OpenBox Window Manager"
|
||||
lxde_openbox_description = "Fast, lightweight window manager with keyboard-driven workflow."
|
||||
|
||||
lxde_pcmanfm_title = "PCManFM File Manager"
|
||||
lxde_pcmanfm_description = "Lightweight file manager with tabbed browsing and desktop management."
|
||||
|
||||
lxde_lxpanel_title = "LXPanel"
|
||||
lxde_lxpanel_description = "Lightweight panel with application menu, task bar, and system tray."
|
||||
|
||||
lxqt_title = "LXQt Desktop"
|
||||
lxqt_description = "A lightweight Qt-based desktop environment."
|
||||
|
||||
lxqt_panel_title = "LXQt Panel"
|
||||
lxqt_panel_description = "Highly configurable panel with widgets and launchers."
|
||||
|
||||
lxqt_pcmanfm_qt_title = "PCManFM-Qt File Manager"
|
||||
lxqt_pcmanfm_qt_description = "Fast file manager with tabbed interface and desktop icons."
|
||||
|
||||
lumina_title = "Lumina Desktop"
|
||||
lumina_description = "A lightweight, plugin-based desktop environment from TrueOS."
|
||||
|
||||
lumina_applications_title = "Lumina Applications"
|
||||
lumina_applications_description = "Native applications for Lumina desktop environment."
|
||||
|
||||
lumina_theme_title = "Lumina Theme Engine"
|
||||
lumina_theme_description = "Full theme support for a consistent visual experience."
|
||||
|
||||
lumina_panel_title = "Lumina Panel"
|
||||
lumina_panel_description = "Flexible panel system with custom widgets."
|
||||
|
||||
mate_title = "MATE Desktop"
|
||||
mate_description = "Traditional desktop environment continued from GNOME 2."
|
||||
|
||||
mate_caja_title = "Caja File Manager"
|
||||
mate_caja_description = "Feature-rich file manager with spatial and browser views."
|
||||
|
||||
mate_settings_title = "MATE Settings"
|
||||
mate_settings_description = "Complete system settings organized by category."
|
||||
|
||||
mate_applications_title = "MATE Applications"
|
||||
mate_applications_description = "Integrated application suite for daily tasks."
|
||||
|
||||
xfce_title = "XFCE Desktop"
|
||||
xfce_description = "Lightweight yet powerful desktop environment."
|
||||
|
||||
xfce_panel_title = "XFCE Panel"
|
||||
xfce_panel_description = "Highly customizable panel with launchers, applets, and menus."
|
||||
|
||||
xfce_thunar_title = "Thunar File Manager"
|
||||
xfce_thunar_description = "Fast and reliable file manager with bulk rename and plugins."
|
||||
|
||||
xfce_settings_title = "XFCE Settings"
|
||||
xfce_settings_description = "Comprehensive settings manager for desktop customization."
|
||||
|
||||
# ── LVM ────────────────────────────────────────────────────
|
||||
lvm_lv_title = "LVM Logical Volumes"
|
||||
lvm_lv_name = "LV Name"
|
||||
lvm_lv_vg = "Volume Group"
|
||||
lvm_lv_add = "Add Logical Volume"
|
||||
lvm_lv_error_vg = "At least one Volume Group must be defined."
|
||||
lvm_lv_error_size = "Entered size exceeds Volume Group capacity."
|
||||
lvm_lv_mountpoint = "Mount Point"
|
||||
lvm_lv_fstype = "File System"
|
||||
lvm_lv_size = "Size (MB, 0=remaining):"
|
||||
lvm_lv_action = "Action"
|
||||
|
||||
|
||||
|
||||
+305
-107
@@ -8,8 +8,11 @@ confirm = "Onayla"
|
||||
# ── Welcome ───────────────────────────────────────────────
|
||||
welcome = "Hoş Geldiniz"
|
||||
welcome_title = "YALI Kurulum Aracına Hoş Geldiniz"
|
||||
welcome_description = "Bu araç size kurulum sürecinde rehberlik edecektir."
|
||||
welcome_description = "Bu araç size kurulum sürecinde rehberlik edecektir. Sisteminize kurulacak olan İşletim Sistemi bilgileri:"
|
||||
select_language = "Dil Seçiniz:"
|
||||
os = "İşletim Sistemi"
|
||||
desktop = "Masaüstü"
|
||||
version = "Sürüm"
|
||||
|
||||
# ── Location ──────────────────────────────────────────────
|
||||
location = "Konum"
|
||||
@@ -72,110 +75,6 @@ execution_description = "Lütfen bekleyin. Bu işlem birkaç dakika sürebilir."
|
||||
start_install = "Kurulumu Başlat"
|
||||
install_starting = "Kurulum başlatılıyor…"
|
||||
|
||||
# ── Slides for PISILINUX ────────────────────────────────────────────
|
||||
welcome_slide_title = "Pisi GNU/Linux'a Hoş Geldiniz"
|
||||
welcome_slide_description = "Pisi; hız, kararlılık ve kullanım kolaylığını bir araya getiren Türkçe destekli bir GNU/Linux dağıtımıdır."
|
||||
package_manager_title = "PISI Paket Yöneticisi"
|
||||
package_manager_description = "Binlerce pakete tek komutla erişin. `pisi install <paket>` ile ihtiyacınız olan her şeyi kolayca kurabilirsiniz."
|
||||
community_title = "Topluluk Desteği"
|
||||
community_description = "forum.pisilinux.org adresindeki aktif topluluğumuz sorularınızı yanıtlamak için hazır. Wiki sayfalarımız da her an erişilebilir."
|
||||
speed_title = "Hız ve Performans"
|
||||
speed_description = "Optimize edilmiş çekirdek ve başlangıç servisleri sayesinde PisiLinux saniyeler içinde açılır ve minimum kaynak kullanır."
|
||||
security_title = "Güvenlik Önce Gelir"
|
||||
security_description = "Düzenli güvenlik güncellemeleri, AppArmor profilleri ve güvenli varsayılan ayarlarla sisteminizi koruyun."
|
||||
customization_title = "Özelleştirme"
|
||||
customization_description = "Masaüstü ortamından tema renklerine, panel düzeninden klavye kısayollarına kadar her şeyi zevkinize göre ayarlayın."
|
||||
|
||||
# ── Slides for BUDGIE ────────────────────────────────────────────
|
||||
budgie_title = "PisiLinux Budgie"
|
||||
budgie_description = "Modern, sade ve şık Budgie masaüstü. GNOME altyapısı üzerine inşa edilmiş, kullanıcı dostudur."
|
||||
budgie_applets_title = "Budgie Desktop Applets"
|
||||
budgie_applets_description = "Budgie'nin panel appletleri sayesinde hava durumu, sistem izleyici, takvim gibi araçları kolayca ekleyin."
|
||||
budgie_raven_title = "Raven Bildirim Merkezi"
|
||||
budgie_raven_description = "Raven panelinden ses seviyesi, medya kontrolleri, bildirimler ve hızlı ayarlara erişin."
|
||||
budgie_gtk_theme_title = "GTK Tema Desteği"
|
||||
budgie_gtk_theme_description = "Budgie, GTK temalarını ve GNOME uygulamalarını sorunsuz çalıştırır, görsel bütünlük sağlar."
|
||||
|
||||
# ── Slides for CINNAMON ────────────────────────────────────────────
|
||||
cinnamon_title = "PisiLinux Cinnamon"
|
||||
cinnamon_description = "Geleneksel masaüstü deneyimini modern özelliklerle birleştiren Cinnamon, güçlü ve esnek bir ortam sunar."
|
||||
cinnamon_panel_title = "Cinnamon Paneli"
|
||||
cinnamon_panel_description = "Panelinizi applet'ler, başlatıcılar ve sistem göstergeleriyle özelleştirin; klasik ama güçlü bir masaüstü deneyimi yaşayın."
|
||||
cinnamon_settings_title = "Ayarlar Yöneticisi"
|
||||
cinnamon_settings_description = "Cinnamon'un kapsamlı Ayarlar Yöneticisi aracılığıyla masaüstünüzün her yönünü özelleştirin."
|
||||
cinnamon_desklets_title = "Cinnamon Desklets"
|
||||
cinnamon_desklets_description = "Masaüstü widget'ları ile notlar, saatler ve sistem bilgileri her zaman görünür kalsın."
|
||||
|
||||
# ── Slides for GNOME ────────────────────────────────────────────
|
||||
gnome_title = "PisiLinux GNOME"
|
||||
gnome_description = "Sade ve odaklı GNOME masaüstü ortamı ile dikkat dağıtıcı unsurları azaltın, işinize konsantre olun."
|
||||
gnome_search_title = "GNOME Arama"
|
||||
gnome_search_description = "Super tuşuna basıp yazmaya başlayın. Uygulama, dosya ve ayarlara anında ulaşın."
|
||||
gnome_extensions_title = "GNOME Eklentileri"
|
||||
gnome_extensions_description = "extensions.gnome.org adresinden yüzlerce eklentiyle masaüstünüzü ihtiyaçlarınıza göre şekillendirin."
|
||||
|
||||
# ── Slides for KDE/Plasma ────────────────────────────────────────────
|
||||
kde_title = "PisiLinux KDE Plasma"
|
||||
kde_description = "Modern, özelleştirilebilir ve güçlü KDE Plasma masaüstü ortamıyla tanışın. Her şey elinizin altında."
|
||||
dolphin_title = "Dolphin Dosya Yöneticisi"
|
||||
dolphin_description = "Sekmeli gezinme, ikili panel ve güçlü arama özelliğiyle Dolphin dosyalarınızı yönetmeyi kolaylaştırır."
|
||||
kde_connect_title = "KDE Bağlan"
|
||||
kde_connect_description = "Telefonunuzu bilgisayarınıza bağlayın. Bildirimler, dosya aktarımı ve klipboard paylaşımı KDE Connect ile mümkün."
|
||||
discover_title = "Discover Yazılım Merkezi"
|
||||
discover_description = "Discover ile uygulamaları görsel arayüzden kolayca bulun, kurun ve güncelleyin."
|
||||
|
||||
# ── Slides for LXQt ────────────────────────────────────────────
|
||||
lxqt_title = "PisiLinux LXQt"
|
||||
lxqt_description = "Hafif, hızlı ve modern LXQt masaüstü ortamı. Kaynak tüketimi düşük, performansı yüksektir."
|
||||
lxqt_panel_title = "LXQt Panel"
|
||||
lxqt_panel_description = "Geleneksel panel düzeni ile görev çubuğu, uygulama başlatıcı ve sistem tepsisi her zaman elinizin altında."
|
||||
lxqt_pcmanfm_qt_title = "PCManFM-Qt Dosya Yöneticisi"
|
||||
lxqt_pcmanfm_qt_description = "Hafif ve hızlı PCManFM-Qt ile dosya işlemlerini kolayca yönetin. Sekmeli gezinme ve özelleştirilebilir arayüz sunar."
|
||||
lxqt_speed_title = "LXQt Hızı"
|
||||
lxqt_speed_description = "LXQt, hız için tasarlanmıştır. Daha hızlı açılır, daha çabuk yanıt verir ve eski donanımları en iyi şekilde kullanır."
|
||||
|
||||
# ── Slides for LXDE ────────────────────────────────────────────
|
||||
lxde_title = "PisiLinux LXDE"
|
||||
lxde_description = "Efsanevi hafif masaüstü LXDE. Çok düşük kaynak tüketimi ve güvenilir yapısıyla tanınır."
|
||||
lxde_openbox_title = "Openbox Tabanlı"
|
||||
lxde_openbox_description = "LXDE, Openbox pencere yöneticisini kullanır. İnce ayarlar ile akıcı bir deneyim sunar."
|
||||
lxde_pcmanfm_title = "PCManFM Dosya Yöneticisi"
|
||||
lxde_pcmanfm_description = "PCManFM, hızlı ve hafif yapısıyla dosya işlemlerinizi kolaylaştırır, ağaç görünümü ve sekme destekler."
|
||||
lxde_lxpanel_title = "LXPanel"
|
||||
lxde_lxpanel_description = "LXPanel, geleneksel masaüstü düzeni ile görev çubuğu, uygulama menüsü ve sistem tepsisi gibi temel özellikleri sunar."
|
||||
|
||||
# ── Slides for LUMINA ────────────────────────────────────────────
|
||||
lumina_title = "PisiLinux Lumina"
|
||||
lumina_description = "Hafif ve bağımsız Lumina masa üstü. Qt tabanlı, BSD ve Linux sistemlerde düzgün çalışan minimal bir ortam."
|
||||
lumina_applications_title = "Uygulama Desteği"
|
||||
lumina_applications_description = "Lumina; temel uygulamalar ve birçok popüler Qt uygulamasıyla uyumlu çalışır, kullanışlı bir deneyim sunar."
|
||||
lumina_theme_title = "Tema Özelleştirme"
|
||||
lumina_theme_description = "Lumina'nın tema sistemiyle renk şemaları ve arayüz stilini kolayca özelleştirin."
|
||||
lumina_panel_title = "Lumina Paneli"
|
||||
lumina_panel_description = "Görev çubuğu, uygulama başlatıcı ve sistem tepsisini içeren sade panel, masa üstünüzü düzenli tutar."
|
||||
|
||||
# ── Slides for MATE ────────────────────────────────────────────
|
||||
mate_title = "PisiLinux MATE"
|
||||
mate_description = "Geleneksel masaüstü düzenini sevenler için MATE. GTK+ 3 ile geliştirilmiş, modern ve akıcı bir deneyim sunar."
|
||||
mate_caja_title = "Caja Dosya Yöneticisi"
|
||||
mate_caja_description = "MATE'in güçlü dosya yöneticisi Caja ile dosya işlemlerinizi kolayca yapın. Çift panel, sekmeli gezinme ve geniş özellikler sunar."
|
||||
mate_settings_title = "MATE Ayarları"
|
||||
mate_settings_description = "Görünüm, ekran, klavye ve daha fazlası için kapsamlı ayarlarla MATE masaüstünüzü özelleştirin."
|
||||
mate_applications_title = "Zengin Uygulama Paketi"
|
||||
mate_applications_description = "MATE; metin editöründen görüntü görüntüleme yazılımına kadar geniş, iyi entegre edilmiş klasik uygulamalar sunar."
|
||||
|
||||
|
||||
# ── Slides for XFCE ────────────────────────────────────────────
|
||||
xfce_title = "PisiLinux XFCE"
|
||||
xfce_description = "Hafif, hızlı ve kullanıcı dostu XFCE masaüstü ortamı. Kaynak tüketimi düşük, performansı yüksektir."
|
||||
xfce_panel_title = "XFCE Panel"
|
||||
xfce_panel_description = "Geleneksel panel düzeni ile görev çubuğu, uygulama menüsü ve sistem tepsisi her zaman elinizin altında."
|
||||
xfce_thunar_title = "Thunar Dosya Yöneticisi"
|
||||
xfce_thunar_description = "Hızlı ve hafif Thunar ile dosya işlemlerinizi kolayca yapın. Ağaç görünümü, sekmeli gezinme ve özelleştirilebilir özellikler sunar."
|
||||
xfce_settings_title = "Ayarlar Merkezi"
|
||||
xfce_settings_description = "Klasik uygulama menüsüne modern bir alternatif. Whisker Menu ile uygulamaları kolayca bulun, favorilerinizi düzenleyin."
|
||||
|
||||
|
||||
# ── Finish ────────────────────────────────────────────────
|
||||
finish = "Tamamlandı"
|
||||
finish_title = "Kurulum Tamamlandı"
|
||||
@@ -205,7 +104,7 @@ mp_size_remaining = "Kalan Alan"
|
||||
|
||||
# ── UI / Genel ────────────────────────────────────────────
|
||||
installer = "YALI Kurulum Aracı"
|
||||
os_name = "PiSi GNU/LİNUX"
|
||||
app_name = "YALI"
|
||||
|
||||
# ── Hata ekranı ───────────────────────────────────────────
|
||||
error_show_log = "▼ Log Detaylarını Göster"
|
||||
@@ -221,6 +120,8 @@ check_fail_warning = "Bir veya daha fazla kritik gereksinim karşılanmıyor. L
|
||||
check_warn_notice = "Bazı önerilen gereksinimler karşılanmıyor. Kurulum devam edebilir."
|
||||
check_all_pass = "Tüm sistem gereksinimleri karşılandı."
|
||||
recheck = "🔄 Yeniden Kontrol Et"
|
||||
rescue_button = "🆘 Kurtarma Kipi"
|
||||
rescue_button_tooltip = "PiSi Linux'u Kurtarma Modunda Yeniden Kur"
|
||||
|
||||
# ── Users (ek) ────────────────────────────────────────────
|
||||
pwd_very_weak = "Çok zayıf"
|
||||
@@ -237,7 +138,7 @@ check_disk_pass = "%{size} GB disk mevcut."
|
||||
check_internet = "İnternet"
|
||||
check_net_pass = "İnternet bağlantısı mevcut."
|
||||
check_net_warn = "İnternet bağlantısı bulunamadı. Çevrimdışı kurulum devam edebilir, ancak güncellemeler ve ek paketler indirilemeyecek."
|
||||
check_boot_mode = "Önyükleme Modu"
|
||||
check_boot_mode = "Önyükleme Kipi"
|
||||
check_uefi_pass = "UEFI modu tespit edildi. GPT kullanılacak."
|
||||
check_bios_pass = "BIOS/Legacy modu tespit edildi. MBR kullanılacak."
|
||||
check_live_sys = "Canlı Sistem"
|
||||
@@ -329,3 +230,300 @@ error_partition_plan_not_found = "Bölümleme planı bulunamadı."
|
||||
error_target_disk_not_selected = "Hedef disk seçilmedi."
|
||||
error_thread_terminated = "İş parçacığı beklenmedik şekilde sonlandı."
|
||||
error_thread_unexpectedly_terminated = "İş parçacığı beklenmedik şekilde sonlandı."
|
||||
|
||||
# ── Summary (ek) ─────────────────────────────────────────────
|
||||
summary_bootloader = "Önyükleyici"
|
||||
summary_datetime = "Tarih & Saat"
|
||||
summary_ntp_enabled = "NTP etkin (otomatik)"
|
||||
summary_root = "Kök (root)"
|
||||
summary_root_enabled = "Parola belirlendi"
|
||||
summary_root_disabled = "Devre dışı (kilitli)"
|
||||
summary_software = "Yazılım"
|
||||
summary_display_manager = "Görüntü Yöneticisi"
|
||||
summary_autologin = "Otomatik oturum açma"
|
||||
summary_autologin_user = "Otomatik oturum açılacak kullanıcı"
|
||||
summary_desktop = "Masaüstü"
|
||||
|
||||
# ── Görüntü Yöneticisi ───────────────────────────────────────
|
||||
display_manager = "Görüntü Yöneticisi"
|
||||
display_manager_title = "Görüntü Yöneticisi Yapılandırması"
|
||||
display_manager_description = "Görüntü yöneticinizi ve masaüstü ortamınızı seçin."
|
||||
display_manager_select = "Görüntü yöneticisi:"
|
||||
display_manager_de = "Masaüstü ortamı:"
|
||||
display_manager_autologin = "Otomatik oturum açma"
|
||||
display_manager_autologin_user = "Otomatik oturum açılacak kullanıcı:"
|
||||
display_manager_autologin_hint = "(ilk kullanıcı)"
|
||||
display_manager_de_not_found = "(algılanamadı)"
|
||||
display_manager_note = "Not: Görüntü yöneticisi, kurulan sistemde varsayılan olarak etkin olacaktır."
|
||||
|
||||
# ── Kullanıcı (ek) ──────────────────────────────────────────────
|
||||
use_same_for_admin = "Yönetici (root) hesabı için aynı parolayı kullan"
|
||||
|
||||
# ── Jobs (ek) ──────────────────────────────────────────────────
|
||||
job_install_packages = "Seçilen paketler kuruluyor"
|
||||
job_ldconfig = "Paylaşımlı kütüphaneler yapılandırılıyor (ldconfig)"
|
||||
job_update_env = "Sistem ortamı güncelleniyor"
|
||||
job_cleanup_live = "Canlı ortam izleri temizleniyor"
|
||||
job_datetime = "Tarih & saat yapılandırılıyor"
|
||||
job_display_manager = "Görüntü yöneticisi yapılandırılıyor"
|
||||
job_netinstall = "Ek paketler kuruluyor"
|
||||
job_setup_lvm = "LVM yapılandırılıyor"
|
||||
|
||||
# ── Lisans ───────────────────────────────────────────────────
|
||||
license = "Lisans"
|
||||
license_title = "GNU Genel Kamu Lisansı"
|
||||
license_description = "Devam etmek için lisans koşullarını okuyun ve kabul edin."
|
||||
license_accept = "GNU Genel Kamu Lisansı koşullarını okudum ve kabul ediyorum."
|
||||
|
||||
# ── Yönetici (root) ─────────────────────────────────────────
|
||||
admin = "Yönetici"
|
||||
admin_title = "Root Parolası"
|
||||
admin_description = "Root (yönetici) hesabı için bir parola belirleyin. Boş bırakılırsa doğrudan root girişi devre dışı kalır."
|
||||
admin_password_label = "Root parolası:"
|
||||
admin_password_confirm_label = "Root parolası (tekrar):"
|
||||
admin_password_short = "Root parolası en az 4 karakter olmalıdır."
|
||||
|
||||
# ── Tarih & Saat ────────────────────────────────────────────
|
||||
datetime = "Tarih & Saat"
|
||||
datetime_title = "Tarih & Saat Ayarları"
|
||||
datetime_description = "Sistem tarihini ve saatini yapılandırın."
|
||||
datetime_ntp_label = "Ağ Zamanı (NTP):"
|
||||
datetime_ntp_on = "Etkin — saat otomatik eşitlenir"
|
||||
datetime_ntp_off = "Devre dışı — elle ayarlanır"
|
||||
datetime_date_label = "Tarih:"
|
||||
datetime_time_label = "Saat:"
|
||||
datetime_year = "Yıl:"
|
||||
datetime_month = "Ay:"
|
||||
datetime_day = "Gün:"
|
||||
datetime_ntp_info = "NTP, kurulumdan sonra sistem saatini ağ üzerinden eşitleyecektir."
|
||||
datetime_manual_info = "Tarih ve saati elle ayarlayın. Sistem bu değerleri kullanacaktır."
|
||||
|
||||
# ── Ağ ──────────────────────────────────────────────────────
|
||||
network = "Ağ"
|
||||
network_title = "Ağ Yapılandırması"
|
||||
network_description = "Ağ bağlantılarını ve vekil sunucu (proxy) ayarlarını yapılandırın."
|
||||
network_connected = "Bağlı:"
|
||||
network_disconnected = "Bağlı değil"
|
||||
network_scan = "🔍 Wi-Fi Ağlarını Tara"
|
||||
network_rescan = "🔄 Yeniden Tara"
|
||||
network_scan_count = "Bulunan ağlar:"
|
||||
network_connect = "Bağlan"
|
||||
network_password_hint = "Parola"
|
||||
network_proxy_label = "Vekil sunucu (proxy) yapılandır:"
|
||||
|
||||
# ── Yazılım ─────────────────────────────────────────────────
|
||||
software = "Yazılım"
|
||||
software_title = "Yazılım Seçimi"
|
||||
software_description = "Hangi yazılımların kurulacağını seçin."
|
||||
software_desktops = "Masaüstü Ortamları"
|
||||
software_desktop_xfce = "XFCE — Hafif ve hızlı"
|
||||
software_desktop_kde = "KDE Plasma — Modern ve özellikli"
|
||||
software_desktop_gnome = "GNOME — Sade ve odaklı"
|
||||
software_desktop_cinnamon = "Cinnamon — Geleneksel ve güçlü"
|
||||
software_additional = "Ek Koleksiyonlar"
|
||||
software_office = "Ofis — LibreOffice, belge araçları"
|
||||
software_development = "Geliştirme — GCC, Git, IDE araçları"
|
||||
software_multimedia = "Multimedya — Kodekler, oynatıcılar, düzenleyiciler"
|
||||
software_minimal = "⚠ Minimal — yalnızca temel sistem (diğerlerini geçersiz kılar)"
|
||||
software_minimal_warning = "'Minimal' seçimi diğer tüm seçimleri geçersiz kılar. Yalnızca temel paketler kurulur."
|
||||
|
||||
# ── Önyükleyici ─────────────────────────────────────────────
|
||||
bootloader = "Önyükleyici"
|
||||
bootloader_title = "Önyükleyici Yapılandırması"
|
||||
bootloader_description = "Önyükleyici (GRUB) ayarlarını yapılandırın."
|
||||
bootloader_device_label = "Aygıta kur:"
|
||||
bootloader_device_hint = "(varsayılan: hedef disk)"
|
||||
bootloader_timeout_label = "Bekleme süresi:"
|
||||
bootloader_timeout_suffix = "saniye"
|
||||
bootloader_password_label = "GRUB parolası (isteğe bağlı):"
|
||||
bootloader_kernel_label = "Çekirdek parametreleri:"
|
||||
bootloader_kernel_hint = "(örn. quiet splash)"
|
||||
|
||||
# ── Kurtarma ────────────────────────────────────────────────
|
||||
rescue = "Kurtarma"
|
||||
rescue_title = "Kurtarma Modu"
|
||||
rescue_description = "Mevcut bir PisiLinux kurulumunu onarın."
|
||||
rescue_no_installations = "Linux bölümü bulunamadı. Lütfen sistemi kontrol edip tekrar deneyin."
|
||||
rescue_scan = "🔍 Tara"
|
||||
rescue_detected = "Algılanan Linux Bölümleri:"
|
||||
rescue_chroot = "📂 Kurtarma Kabuğu (chroot)"
|
||||
rescue_chroot_start = "Chroot kabuğu başlatılıyor…"
|
||||
rescue_grub = "🔧 GRUB'u Yeniden Kur"
|
||||
rescue_grub_start = "GRUB yeniden kuruluyor…"
|
||||
rescue_return = "↩ Normal Kuruluma Dön"
|
||||
rescue_not_available = "Kurtarma modu: mevcut Linux kurulumu bulunamadı."
|
||||
rescue_pisi_history = "📜 Pisi Geçmişi Geri Alma"
|
||||
rescue_pisi_history_title = "Pisi Paket Geçmişi"
|
||||
rescue_pisi_history_desc = "Bir geçmiş kaydı seçin ve bu noktaya dönmek için Geri Al'a tıklayın."
|
||||
rescue_pisi_history_scan = "🔍 Geçmişi Listele"
|
||||
rescue_pisi_history_empty = "Paket geçmişi bulunamadı veya okunamadı."
|
||||
rescue_pisi_takeback = "↩ Bu Noktaya Geri Al"
|
||||
rescue_pisi_takeback_start = "Pisi takeback çalıştırılıyor…"
|
||||
rescue_pisi_history_ok = "Geri alma başarıyla tamamlandı."
|
||||
rescue_pisi_history_err = "Hata: %{err}"
|
||||
|
||||
# ── LUKS ────────────────────────────────────────────────────
|
||||
luks_enable_root = "Kök bölümünü şifrele (LUKS)"
|
||||
luks_password = "Şifreleme parolası:"
|
||||
luks_password_weak = "Parola çok kısa (en az 4 karakter)"
|
||||
|
||||
# ── Netinstall ──────────────────────────────────────────────
|
||||
netinstall = "Yazılım Seçimi"
|
||||
netinstall_title = "Ek Yazılım"
|
||||
netinstall_description = "Kurulacak ek paket gruplarını seçin."
|
||||
netinstall_package_count = "paket"
|
||||
netinstall_selected = "seçildi"
|
||||
|
||||
# ── Medya Kontrolü ──────────────────────────────────────────
|
||||
media_check = "Medya Kontrolü"
|
||||
media_check_title = "Kurulum Medyasını Doğrula"
|
||||
media_check_description = "ISO veya USB sürücünüzün bütünlüğünü kontrol edin."
|
||||
media_check_scan = "🔍 Medyayı Tara"
|
||||
media_check_select = "Doğrulanacak dosyayı seçin:"
|
||||
media_check_running = "Kontrol ediliyor… lütfen bekleyin."
|
||||
media_check_ok = "✅ Medya bütünlüğü başarıyla doğrulandı."
|
||||
media_check_fail = "❌ Medya bütünlük kontrolü BAŞARISIZ! Lütfen yeniden indirin."
|
||||
media_check_no_md5 = "⚠️ md5sum veya sha256sum aracı bulunamadı."
|
||||
media_check_file_not_found = "⚠️ Seçilen dosya bulunamadı."
|
||||
media_check_path_label = "Dosya yolu:"
|
||||
media_check_path_hint = "örn. /run/live/medium/pisilinux.iso"
|
||||
media_check_algorithm = "Algoritma:"
|
||||
job_media_check = "Kurulum medyası doğrulanıyor"
|
||||
|
||||
# ── LVM ─────────────────────────────────────────────────────
|
||||
lvm_lv_title = "LVM Mantıksal Birimler"
|
||||
lvm_lv_name = "LV Adı"
|
||||
lvm_lv_vg = "Birim Grubu"
|
||||
lvm_lv_add = "Mantıksal Birim Ekle"
|
||||
lvm_lv_error_vg = "En az bir Birim Grubu tanımlanmalıdır."
|
||||
lvm_lv_error_size = "Girilen boyut, Birim Grubu kapasitesini aşıyor."
|
||||
lvm_lv_mountpoint = "Bağlama Noktası"
|
||||
lvm_lv_fstype = "Dosya Sistemi"
|
||||
lvm_lv_size = "Boyut (MB, 0=kalan):"
|
||||
lvm_lv_action = "İşlem"
|
||||
|
||||
# ── CLI / Otomatik Kurulum ─────────────────────────────────
|
||||
hostname = "Bilgisayar adı"
|
||||
timezone = "Zaman dilimi"
|
||||
username = "Kullanıcı adı"
|
||||
|
||||
# ── Slayt Gösterisi (yedek) ────────────────────────────────
|
||||
welcome_slide_title = "Pisi Linux'a Hoş Geldiniz"
|
||||
welcome_slide_description = "Modern, hızlı ve güvenli bir GNU/Linux dağıtımı."
|
||||
|
||||
package_manager_title = "Pisi Paket Yöneticisi"
|
||||
package_manager_description = "Bağımlılık çözümü, geçmiş geri alma ve atomik güncellemeler ile güçlü bir paket yöneticisi."
|
||||
|
||||
community_title = "Topluluk Odaklı"
|
||||
community_description = "Topluluk tarafından, topluluk için geliştirilmiştir. Pisi Linux özgür ve açık kaynaktır."
|
||||
|
||||
speed_title = "Hız İçin Optimize Edilmiş"
|
||||
speed_description = "Hem modern hem de eski donanımlarda hızlı çalışacak şekilde tasarlanmıştır."
|
||||
|
||||
security_title = "Önce Güvenlik"
|
||||
security_description = "Düzenli güvenlik güncellemeleri ve sağlam bir izin sistemi sisteminizi güvende tutar."
|
||||
|
||||
customization_title = "Tam Özelleştirme"
|
||||
customization_description = "Kurulum sırasında masaüstünüzü, uygulamalarınızı ve görünümünüzü seçin."
|
||||
|
||||
budgie_title = "Budgie Masaüstü"
|
||||
budgie_description = "Sadeliği hedefleyen modern ve şık bir masaüstü ortamı."
|
||||
|
||||
budgie_applets_title = "Budgie Applet'leri"
|
||||
budgie_applets_description = "Bildirimler, sistem tepsisi ve daha fazlası için özelleştirilebilir applet'ler."
|
||||
|
||||
budgie_raven_title = "Budgie Raven"
|
||||
budgie_raven_description = "Hızlı erişim için bildirim merkezi ve ayar paneli."
|
||||
|
||||
budgie_gtk_theme_title = "GTK Tema Entegrasyonu"
|
||||
budgie_gtk_theme_description = "Tutarlı uygulama görünümü için kusursuz GTK tema desteği."
|
||||
|
||||
cinnamon_title = "Cinnamon Masaüstü"
|
||||
cinnamon_description = "Modern özelliklere sahip geleneksel bir masaüstü düzeni."
|
||||
|
||||
cinnamon_panel_title = "Cinnamon Paneli"
|
||||
cinnamon_panel_description = "Applet'ler, başlatıcılar ve tepsi simgeleri ile esnek panel sistemi."
|
||||
|
||||
cinnamon_settings_title = "Cinnamon Ayarları"
|
||||
cinnamon_settings_description = "Menüden erişilebilen kapsamlı sistem ayarları."
|
||||
|
||||
cinnamon_desklets_title = "Cinnamon Desklet'leri"
|
||||
cinnamon_desklets_description = "Hava durumu, saat, sistem izleme ve daha fazlası için etkileşimli desklet'ler."
|
||||
|
||||
gnome_title = "GNOME Masaüstü"
|
||||
gnome_description = "Sade, dikkat dağıtmayan bir masaüstü ortamı."
|
||||
|
||||
gnome_search_title = "GNOME Arama"
|
||||
gnome_search_description = "Uygulamalar, dosyalar ve ayarlar arasında anında arama."
|
||||
|
||||
gnome_extensions_title = "GNOME Eklentileri"
|
||||
gnome_extensions_description = "Topluluk tarafından geliştirilen eklentilerle masaüstünüzü genişletin."
|
||||
|
||||
kde_title = "KDE Plasma Masaüstü"
|
||||
kde_description = "Özellik dolu, son derece özelleştirilebilir masaüstü ortamı."
|
||||
|
||||
dolphin_title = "Dolphin Dosya Yöneticisi"
|
||||
dolphin_description = "Bölünmüş ekran görünümü ve güçlü arama ile sezgisel dosya yöneticisi."
|
||||
|
||||
kde_connect_title = "KDE Connect"
|
||||
kde_connect_description = "Telefonunuzu masaüstünüzle kusursuzca bütünleştirin."
|
||||
|
||||
discover_title = "Discover Yazılım Merkezi"
|
||||
discover_description = "Tek tıkla uygulamalara göz atın ve kurun."
|
||||
|
||||
lxde_title = "LXDE Masaüstü"
|
||||
lxde_description = "Eski donanımlar için hafif masaüstü ortamı."
|
||||
|
||||
lxde_openbox_title = "OpenBox Pencere Yöneticisi"
|
||||
lxde_openbox_description = "Klavye odaklı iş akışı ile hızlı ve hafif pencere yöneticisi."
|
||||
|
||||
lxde_pcmanfm_title = "PCManFM Dosya Yöneticisi"
|
||||
lxde_pcmanfm_description = "Sekmeli gezinti ve masaüstü yönetimi ile hafif dosya yöneticisi."
|
||||
|
||||
lxde_lxpanel_title = "LXPanel"
|
||||
lxde_lxpanel_description = "Uygulama menüsü, görev çubuğu ve sistem tepsisi ile hafif panel."
|
||||
|
||||
lxqt_title = "LXQt Masaüstü"
|
||||
lxqt_description = "Qt tabanlı hafif bir masaüstü ortamı."
|
||||
|
||||
lxqt_panel_title = "LXQt Paneli"
|
||||
lxqt_panel_description = "Araçlar ve başlatıcılar ile son derece yapılandırılabilir panel."
|
||||
|
||||
lxqt_pcmanfm_qt_title = "PCManFM-Qt Dosya Yöneticisi"
|
||||
lxqt_pcmanfm_qt_description = "Sekmeli arayüz ve masaüstü simgeleri ile hızlı dosya yöneticisi."
|
||||
|
||||
lumina_title = "Lumina Masaüstü"
|
||||
lumina_description = "TrueOS'tan hafif, eklenti tabanlı bir masaüstü ortamı."
|
||||
|
||||
lumina_applications_title = "Lumina Uygulamaları"
|
||||
lumina_applications_description = "Lumina masaüstü ortamı için yerel uygulamalar."
|
||||
|
||||
lumina_theme_title = "Lumina Tema Motoru"
|
||||
lumina_theme_description = "Tutarlı bir görsel deneyim için tam tema desteği."
|
||||
|
||||
lumina_panel_title = "Lumina Paneli"
|
||||
lumina_panel_description = "Özel araçlar ile esnek panel sistemi."
|
||||
|
||||
mate_title = "MATE Masaüstü"
|
||||
mate_description = "GNOME 2'den devam eden geleneksel masaüstü ortamı."
|
||||
|
||||
mate_caja_title = "Caja Dosya Yöneticisi"
|
||||
mate_caja_description = "Uzamsal ve tarayıcı görünümleri ile özellik dolu dosya yöneticisi."
|
||||
|
||||
mate_settings_title = "MATE Ayarları"
|
||||
mate_settings_description = "Kategoriye göre düzenlenmiş komple sistem ayarları."
|
||||
|
||||
mate_applications_title = "MATE Uygulamaları"
|
||||
mate_applications_description = "Günlük işler için bütünleşik uygulama paketi."
|
||||
|
||||
xfce_title = "XFCE Masaüstü"
|
||||
xfce_description = "Hafif ancak güçlü bir masaüstü ortamı."
|
||||
|
||||
xfce_panel_title = "XFCE Paneli"
|
||||
xfce_panel_description = "Başlatıcılar, applet'ler ve menüler ile son derece özelleştirilebilir panel."
|
||||
|
||||
xfce_thunar_title = "Thunar Dosya Yöneticisi"
|
||||
xfce_thunar_description = "Toplu yeniden adlandırma ve eklentiler ile hızlı ve güvenilir dosya yöneticisi."
|
||||
|
||||
xfce_settings_title = "XFCE Ayarları"
|
||||
xfce_settings_description = "Masaüstü özelleştirmesi için kapsamlı ayar yöneticisi."
|
||||
|
||||
+86
-18
@@ -81,12 +81,8 @@ fn check_ram() -> CheckResult {
|
||||
|
||||
/// En az 10 GB boş disk alanı kontrolü.
|
||||
fn check_disk_space() -> CheckResult {
|
||||
use sysinfo::Disks;
|
||||
let disks = Disks::new_with_refreshed_list();
|
||||
let max_gb = disks.iter()
|
||||
.map(|d| d.total_space() / 1024 / 1024 / 1024)
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
// sysinfo yerine doğrudan kernel'in gördüğü blok aygıtı boyutunu alıyoruz.
|
||||
let max_gb = get_max_block_device_gb();
|
||||
|
||||
if max_gb < 10 {
|
||||
CheckResult::fail(
|
||||
@@ -99,10 +95,82 @@ fn check_disk_space() -> CheckResult {
|
||||
t!("check_disk_warn", size = max_gb),
|
||||
)
|
||||
} else {
|
||||
CheckResult::pass(t!("check_disk_space"), t!("check_disk_pass", size = max_gb))
|
||||
CheckResult::pass(
|
||||
t!("check_disk_space"),
|
||||
t!("check_disk_pass", size = max_gb)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
use std::fs;
|
||||
|
||||
/// Sistemdeki en büyük fiziksel/sanal blok aygıtının boyutunu GB cinsinden döndürür.
|
||||
///
|
||||
/// Önce `lsblk -d` ile dener (yalnızca disk düzeyindeki aygıtlar, bölümler hariç).
|
||||
/// lsblk yoksa veya başarısız olursa `/sys/block` ile fallback yapar;
|
||||
/// `/sys/block` yalnızca tam diskleri içerdiğinden bölüm girişleri karışmaz.
|
||||
fn get_max_block_device_gb() -> u64 {
|
||||
let mut max_gb = 0u64;
|
||||
|
||||
// ── 1. Birincil yöntem: lsblk -d (partition.rs ile tutarlı) ──────────────
|
||||
let lsblk_out = std::process::Command::new("lsblk")
|
||||
.args(["-d", "-o", "NAME,SIZE", "-b", "--noheadings"])
|
||||
.output();
|
||||
|
||||
if let Ok(o) = lsblk_out {
|
||||
if o.status.success() {
|
||||
let text = String::from_utf8_lossy(&o.stdout);
|
||||
for line in text.lines() {
|
||||
let mut tokens = line.split_whitespace();
|
||||
|
||||
let name = match tokens.next() { Some(n) => n, None => continue };
|
||||
|
||||
// loop, ram, zram, sr (CD-ROM) aygıtlarını atla
|
||||
if name.starts_with("loop")
|
||||
|| name.starts_with("ram")
|
||||
|| name.starts_with("sr")
|
||||
|| name.starts_with("zram")
|
||||
{ continue; }
|
||||
|
||||
let size_str = match tokens.next() { Some(s) => s, None => continue };
|
||||
let size_bytes: u64 = size_str.parse().unwrap_or(0);
|
||||
if size_bytes == 0 { continue; }
|
||||
|
||||
let size_gb = size_bytes / 1_073_741_824;
|
||||
if size_gb > max_gb { max_gb = size_gb; }
|
||||
}
|
||||
// lsblk başarılıysa ve en az bir disk bulduysa döndür
|
||||
if max_gb > 0 { return max_gb; }
|
||||
}
|
||||
}
|
||||
|
||||
// ── 2. Fallback: /sys/block (yalnızca tam diskler — bölüm yok) ───────────
|
||||
// /sys/class/block aksine /sys/block dizini YALNIZCA tam disk girişlerini
|
||||
// içerir; sda1, nvme0n1p1 gibi bölüm sembolik bağlantıları burada bulunmaz.
|
||||
if let Ok(entries) = fs::read_dir("/sys/block") {
|
||||
for entry in entries.flatten() {
|
||||
let name = entry.file_name().into_string().unwrap_or_default();
|
||||
|
||||
if name.starts_with("loop")
|
||||
|| name.starts_with("ram")
|
||||
|| name.starts_with("zram")
|
||||
|| name.starts_with("sr")
|
||||
{ continue; }
|
||||
|
||||
let size_path = entry.path().join("size");
|
||||
if let Ok(size_str) = fs::read_to_string(&size_path) {
|
||||
// sysfs 'size' dosyası: 512 byte'lık sektör sayısı
|
||||
if let Ok(sectors) = size_str.trim().parse::<u64>() {
|
||||
let size_gb = (sectors * 512) / 1_073_741_824;
|
||||
if size_gb > max_gb { max_gb = size_gb; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
max_gb
|
||||
}
|
||||
|
||||
/// İnternet bağlantısı kontrolü (isteğe bağlı).
|
||||
fn check_internet() -> CheckResult {
|
||||
// DNS çözümlemesi ile basit kontrol
|
||||
@@ -150,19 +218,19 @@ fn check_cpu_arch() -> CheckResult {
|
||||
}
|
||||
}
|
||||
|
||||
/// Canlı sistem ortamı kontrolü.
|
||||
/// Canlı sistem ortamı kontrolü — PyQt yali'deki gibi:
|
||||
/// /bootmnt varsa kaynak orası (/bootmnt/pisi/pisi.sqfs),
|
||||
/// yoksa /mnt/cdrom/pisi/pisi.sqfs kontrol edilir.
|
||||
fn check_live_env() -> CheckResult {
|
||||
let source = "/run/livecd/squashfs-root";
|
||||
if !Path::new(source).exists() {
|
||||
CheckResult::fail(
|
||||
t!("check_live_sys"),
|
||||
t!("check_live_fail"),
|
||||
)
|
||||
let sqfs = if Path::new("/bootmnt").exists() {
|
||||
"/bootmnt/pisi/pisi.sqfs"
|
||||
} else {
|
||||
CheckResult::pass(
|
||||
t!("check_live_sys"),
|
||||
t!("check_live_pass"),
|
||||
)
|
||||
"/mnt/cdrom/pisi/pisi.sqfs"
|
||||
};
|
||||
if Path::new(sqfs).exists() {
|
||||
CheckResult::pass(t!("check_live_sys"), t!("check_live_pass"))
|
||||
} else {
|
||||
CheckResult::fail(t!("check_live_sys"), t!("check_live_fail"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+99
-183
@@ -1,216 +1,132 @@
|
||||
//! Otomatik kurulum (answer file) desteği.
|
||||
//! Answer file yapıları, yükleme ve state'e uygulama.
|
||||
//!
|
||||
//! Kullanım:
|
||||
//! yali-rs --auto-install /path/to/answer.toml
|
||||
//!
|
||||
//! Answer file formatı (TOML):
|
||||
//!
|
||||
//! [install]
|
||||
//! disk = "/dev/sda"
|
||||
//! timezone = "Europe/Istanbul"
|
||||
//! locale = "tr_TR.UTF-8"
|
||||
//! keyboard = "tr"
|
||||
//!
|
||||
//! [user]
|
||||
//! username = "pisi"
|
||||
//! password = "changeme"
|
||||
//! hostname = "pisilinux"
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::path::Path;
|
||||
//! Job kuyruğu ve Job struct'ları `src/jobs/` modülündedir.
|
||||
|
||||
pub mod checker;
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// ANSWER FILE YAPISI
|
||||
// ANSWER FILE: VERİ YAPILARI
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
/// `[install]` bölümündeki alanlar.
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct InstallConfig {
|
||||
pub disk: String,
|
||||
#[serde(default = "default_timezone")]
|
||||
pub timezone: String,
|
||||
#[serde(default = "default_locale")]
|
||||
pub locale: String,
|
||||
#[serde(default = "default_keyboard")]
|
||||
pub keyboard: String,
|
||||
#[serde(default)]
|
||||
pub keyboard_variant: String,
|
||||
#[serde(default = "default_source")]
|
||||
pub source: String,
|
||||
#[serde(default = "default_mount")]
|
||||
pub mount: String,
|
||||
}
|
||||
|
||||
/// `[user]` bölümündeki alanlar.
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct UserConfig {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
#[serde(default = "default_hostname")]
|
||||
pub hostname: String,
|
||||
}
|
||||
|
||||
/// Answer file'ın tamamı (`--auto-install <dosya.toml>`).
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct AnswerFile {
|
||||
pub install: InstallConfig,
|
||||
pub user: UserConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct InstallConfig {
|
||||
/// Hedef disk aygıtı. Örn: "/dev/sda", "/dev/nvme0n1"
|
||||
pub disk: String,
|
||||
|
||||
/// Zaman dilimi. Örn: "Europe/Istanbul"
|
||||
#[serde(default = "default_timezone")]
|
||||
pub timezone: String,
|
||||
|
||||
/// Sistem locale. Örn: "tr_TR.UTF-8"
|
||||
#[serde(default = "default_locale")]
|
||||
pub locale: String,
|
||||
|
||||
/// Klavye düzeni. Örn: "tr"
|
||||
#[serde(default = "default_keyboard")]
|
||||
pub keyboard: String,
|
||||
|
||||
/// Klavye varyantı. Örn: "f" (Türkçe F için)
|
||||
#[serde(default)]
|
||||
pub keyboard_variant: String,
|
||||
|
||||
/// Kaynak dizin (canlı sistem). Varsayılan: /run/livecd/squashfs-root/
|
||||
#[serde(default = "default_source")]
|
||||
pub source: String,
|
||||
|
||||
/// Hedef bağlama noktası. Varsayılan: /mnt
|
||||
#[serde(default = "default_mount")]
|
||||
pub mount: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UserConfig {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub hostname: String,
|
||||
}
|
||||
|
||||
fn default_timezone() -> String { "Europe/Istanbul".into() }
|
||||
fn default_locale() -> String { "tr_TR.UTF-8".into() }
|
||||
fn default_keyboard() -> String { "tr".into() }
|
||||
fn default_source() -> String { "/run/livecd/squashfs-root/".into() }
|
||||
fn default_mount() -> String { "/mnt".into() }
|
||||
fn default_timezone() -> String { "Europe/Istanbul".to_string() }
|
||||
fn default_locale() -> String { "tr_TR.UTF-8".to_string() }
|
||||
fn default_keyboard() -> String { "tr".to_string() }
|
||||
fn default_source() -> String { "/run/livecd/squashfs-root/".to_string() }
|
||||
fn default_mount() -> String { "/mnt".to_string() }
|
||||
fn default_hostname() -> String { "pisilinux".to_string() }
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// DOĞRULAMA
|
||||
// ANSWER FILE: YÜKLE ve UYGULA
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AnswerError {
|
||||
Io(std::io::Error),
|
||||
Parse(toml::de::Error),
|
||||
Validation(Vec<String>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AnswerError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AnswerError::Io(e) => write!(f, "Dosya okuma hatası: {}", e),
|
||||
AnswerError::Parse(e) => write!(f, "TOML ayrıştırma hatası: {}", e),
|
||||
AnswerError::Validation(v) => write!(f, "Doğrulama hataları:\n{}", v.join("\n")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Answer dosyasını okuyup ayrıştırır ve doğrular.
|
||||
pub fn load(path: &Path) -> Result<AnswerFile, AnswerError> {
|
||||
/// TOML answer dosyasını diskten okur ve ayrıştırır.
|
||||
pub fn load(path: &std::path::Path) -> Result<AnswerFile, String> {
|
||||
let content = std::fs::read_to_string(path)
|
||||
.map_err(AnswerError::Io)?;
|
||||
|
||||
let af: AnswerFile = toml::from_str(&content)
|
||||
.map_err(AnswerError::Parse)?;
|
||||
|
||||
validate(&af)?;
|
||||
Ok(af)
|
||||
.map_err(|e| format!("Answer file okunamadı '{}': {}", path.display(), e))?;
|
||||
toml::from_str(&content)
|
||||
.map_err(|e| format!("Answer file ayrıştırılamadı: {}", e))
|
||||
}
|
||||
|
||||
fn validate(af: &AnswerFile) -> Result<(), AnswerError> {
|
||||
let mut errors: Vec<String> = Vec::new();
|
||||
/// `AnswerFile` içeriğini `GlobalState`'e uygular.
|
||||
/// Disk boyutunu `lsblk` ile sorgular ve `partition_plan` oluşturur.
|
||||
pub fn apply_to_state(af: &AnswerFile, state: &mut crate::installer::GlobalState) {
|
||||
use crate::installer::{DiskInfo, PartitionPlan, PartitionTableType};
|
||||
|
||||
// Disk kontrolü
|
||||
if !af.install.disk.starts_with("/dev/") {
|
||||
errors.push(format!(
|
||||
"Geçersiz disk yolu '{}'. '/dev/' ile başlamalı.",
|
||||
af.install.disk
|
||||
));
|
||||
}
|
||||
if !Path::new(&af.install.disk).exists() {
|
||||
errors.push(format!(
|
||||
"Disk '{}' bulunamadı. Mevcut diskler için 'lsblk' komutunu çalıştırın.",
|
||||
af.install.disk
|
||||
));
|
||||
}
|
||||
|
||||
// Kullanıcı adı doğrulaması (UsersStep ile aynı kural)
|
||||
let un = &af.user.username;
|
||||
if un.is_empty() || un.len() > 32 {
|
||||
errors.push("Kullanıcı adı 1–32 karakter arasında olmalı.".into());
|
||||
} else {
|
||||
let valid = un.chars().next().map(|c| c.is_ascii_lowercase() || c == '_').unwrap_or(false)
|
||||
&& un.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-');
|
||||
if !valid {
|
||||
errors.push(format!(
|
||||
"Geçersiz kullanıcı adı '{}'. Yalnızca küçük harf, rakam, - ve _ kullanılabilir.",
|
||||
un
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Şifre uzunluğu
|
||||
if af.user.password.len() < 6 {
|
||||
errors.push("Şifre en az 6 karakter olmalı.".into());
|
||||
}
|
||||
|
||||
// Hostname
|
||||
let hn = &af.user.hostname;
|
||||
if hn.is_empty() || hn.len() > 63 || hn.starts_with('-') || hn.ends_with('-')
|
||||
|| !hn.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')
|
||||
{
|
||||
errors.push(format!("Geçersiz hostname '{}'.", hn));
|
||||
}
|
||||
|
||||
if errors.is_empty() { Ok(()) } else { Err(AnswerError::Validation(errors)) }
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// GLOBALSTATE'E UYGULA
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
use crate::installer::GlobalState;
|
||||
use crate::steps::partition::PartitionStep;
|
||||
use crate::installer::InstallerStep;
|
||||
|
||||
/// Answer file verilerini `GlobalState`'e yazar.
|
||||
/// Bu işlemden sonra `PartitionStep::on_enter()` çağrılarak
|
||||
/// disk listesi yenilenebilir ve plan oluşturulabilir.
|
||||
pub fn apply_to_state(af: &AnswerFile, state: &mut GlobalState) {
|
||||
// Temel alanlar
|
||||
state.timezone = af.install.timezone.clone();
|
||||
state.keyboard_layout = af.install.keyboard.clone();
|
||||
state.keyboard_variant = af.install.keyboard_variant.clone();
|
||||
state.selected_disk = Some(af.install.disk.clone());
|
||||
state.erase_disk = true;
|
||||
state.username = af.user.username.clone();
|
||||
state.password = af.user.password.clone();
|
||||
state.password_confirm = af.user.password.clone();
|
||||
state.hostname = af.user.hostname.clone();
|
||||
state.selected_disk = Some(af.install.disk.clone());
|
||||
state.erase_disk = true;
|
||||
state.language = if af.install.locale.starts_with("tr") { "tr" } else { "en" }.to_string();
|
||||
|
||||
// Locale'den dil kodunu çıkar: "tr_TR.UTF-8" → "tr"
|
||||
state.language = af.install.locale
|
||||
.split('_')
|
||||
.next()
|
||||
.unwrap_or("tr")
|
||||
.to_string();
|
||||
// Disk boyutunu lsblk ile sorgula
|
||||
let disk_info: Option<DiskInfo> = (|| {
|
||||
let out = std::process::Command::new("lsblk")
|
||||
.args(["-d", "-b", "-o", "NAME,SIZE,MODEL", "--noheadings", &af.install.disk])
|
||||
.output()
|
||||
.ok()?;
|
||||
if !out.status.success() { return None; }
|
||||
let text = String::from_utf8_lossy(&out.stdout);
|
||||
let line = text.lines().next()?;
|
||||
let mut parts = line.split_whitespace();
|
||||
let name = parts.next()?.to_string();
|
||||
let bytes: u64 = parts.next()?.parse().ok()?;
|
||||
let model = parts.collect::<Vec<_>>().join(" ");
|
||||
Some(DiskInfo {
|
||||
name: format!("/dev/{}", name),
|
||||
model: if model.is_empty() { "Unknown".to_string() } else { model },
|
||||
size_gb: bytes / 1_073_741_824,
|
||||
size_bytes: bytes,
|
||||
})
|
||||
})();
|
||||
|
||||
// Bölümleme planını hesapla
|
||||
let is_uefi = Path::new("/sys/firmware/efi").exists();
|
||||
let mut ps = PartitionStep::default();
|
||||
ps.on_enter(state);
|
||||
// Partition planını hesapla
|
||||
if let Some(info) = disk_info {
|
||||
let is_uefi = std::path::Path::new("/sys/firmware/efi").exists();
|
||||
let efi_mb = if is_uefi { 512u64 } else { 0 };
|
||||
let total_mb = info.size_bytes / 1024 / 1024;
|
||||
|
||||
// Seçili diski bul ve plan oluştur
|
||||
if let Some(disk) = state.available_disks.iter().find(|d| d.name == af.install.disk).cloned() {
|
||||
use crate::installer::{PartitionPlan, PartitionTableType};
|
||||
let total_mb = disk.size_bytes / 1024 / 1024;
|
||||
let efi_mb = if is_uefi { 512 } else { 0 };
|
||||
let swap_mb = recommended_swap_mb();
|
||||
let root_mb = total_mb.saturating_sub(efi_mb + swap_mb + 512);
|
||||
state.partition_plan = Some(PartitionPlan {
|
||||
disk: disk.name.clone(),
|
||||
table_type: if is_uefi { PartitionTableType::Gpt } else { PartitionTableType::Mbr },
|
||||
efi_mb,
|
||||
swap_mb,
|
||||
root_mb,
|
||||
});
|
||||
// Tavsiye edilen swap: RAM * 1.5, min 512 MB, max 8192 MB
|
||||
let mut sys = sysinfo::System::new();
|
||||
sys.refresh_memory();
|
||||
let ram_mb = sys.total_memory() / 1024 / 1024;
|
||||
let swap_mb = (ram_mb * 3 / 2).clamp(512, 8192);
|
||||
|
||||
let overhead = efi_mb + swap_mb + 512;
|
||||
let root_mb = total_mb.saturating_sub(overhead);
|
||||
|
||||
if root_mb >= 6144 && info.size_gb >= 10 {
|
||||
state.partition_plan = Some(PartitionPlan {
|
||||
disk: info.name.clone(),
|
||||
table_type: if is_uefi { PartitionTableType::Gpt } else { PartitionTableType::Mbr },
|
||||
efi_mb,
|
||||
swap_mb,
|
||||
root_mb,
|
||||
encrypt_root: false,
|
||||
luks_password: String::new(),
|
||||
});
|
||||
}
|
||||
|
||||
state.available_disks.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
fn recommended_swap_mb() -> u64 {
|
||||
use sysinfo::System;
|
||||
let mut sys = System::new();
|
||||
sys.refresh_memory();
|
||||
let ram_mb = sys.total_memory() / 1024 / 1024;
|
||||
let swap = if ram_mb <= 2048 { ram_mb } else if ram_mb <= 8192 { ram_mb / 2 } else { 4096 };
|
||||
swap.clamp(512, 8192)
|
||||
}
|
||||
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
//! Yali-RS görsel özelleştirme (branding) yapılandırması.
|
||||
//!
|
||||
//! `branding.toml` dosyasını okur ve tüm sabit kodlanmış görsel yollarını
|
||||
//! çalışma zamanında çözümler. Geliştiriciler yali-rs koduna dokunmadan
|
||||
//! yalnızca `branding.toml` ile logo, slayt görseli ve renk değiştirebilir.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct BrandingConfig {
|
||||
#[serde(default)]
|
||||
pub general: GeneralConfig,
|
||||
#[serde(default)]
|
||||
pub slides: SlidesConfig,
|
||||
#[serde(default)]
|
||||
pub theme: ThemeConfig,
|
||||
#[serde(default)]
|
||||
pub oem: OemConfig,
|
||||
}
|
||||
|
||||
// ── [general] ────────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct GeneralConfig {
|
||||
/// Kurulum penceresinin başlığı.
|
||||
#[serde(default = "default_title")]
|
||||
pub title: String,
|
||||
|
||||
/// Sol kenar çubuğunda gösterilen dağıtım ismi.
|
||||
#[serde(default = "default_subtitle")]
|
||||
pub subtitle: String,
|
||||
|
||||
/// Sol kenar çubuğu için Yali logosu dosya yolu.
|
||||
#[serde(default = "default_yali_logo")]
|
||||
pub yali_logo: String,
|
||||
|
||||
/// Kurulum ana sayfasında gösterilen PisiLinux logosu (koyu tema).
|
||||
#[serde(default = "default_pisi_logo_dark")]
|
||||
pub pisi_logo_dark: String,
|
||||
|
||||
/// Kurulum ana sayfasında gösterilen PisiLinux logosu (açık tema).
|
||||
#[serde(default = "default_pisi_logo_light")]
|
||||
pub pisi_logo_light: String,
|
||||
}
|
||||
|
||||
impl Default for GeneralConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
title: default_title(),
|
||||
subtitle: default_subtitle(),
|
||||
yali_logo: default_yali_logo(),
|
||||
pisi_logo_dark: default_pisi_logo_dark(),
|
||||
pisi_logo_light: default_pisi_logo_light(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── [slides] ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Tek bir slaytın içeriği.
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct SlideItem {
|
||||
/// [slides.icons] tablosundaki ikon anahtar adı.
|
||||
pub icon: String,
|
||||
/// Slayt başlığı.
|
||||
pub title: String,
|
||||
/// Slayt açıklama metni.
|
||||
pub description: String,
|
||||
/// Yalnızca bu masaüstü ortamında göster (boş = hepsinde).
|
||||
/// Örnek: "xfce", "kde", "gnome"
|
||||
#[serde(default)]
|
||||
pub desktop: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct SlidesConfig {
|
||||
/// Slayt geçiş süresi (saniye).
|
||||
#[serde(default = "default_interval")]
|
||||
pub interval_secs: u64,
|
||||
|
||||
/// Slayt ikonu anahtar sözcüğü → dosya yolu eşlemesi.
|
||||
#[serde(default)]
|
||||
pub icons: HashMap<String, String>,
|
||||
|
||||
/// branding.toml içinde [[slides.items]] ile tanımlanan slayt listesi.
|
||||
/// Boşsa slideshow.rs içindeki sabit slaytlar kullanılır.
|
||||
#[serde(default)]
|
||||
pub items: Vec<SlideItem>,
|
||||
}
|
||||
|
||||
// ── [theme] ──────────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct ThemeConfig {
|
||||
#[serde(default = "default_primary")]
|
||||
pub primary: String,
|
||||
#[serde(default = "default_accent")]
|
||||
pub accent: String,
|
||||
#[serde(default = "default_background")]
|
||||
pub background: String,
|
||||
#[serde(default = "default_text")]
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl Default for ThemeConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
primary: default_primary(),
|
||||
accent: default_accent(),
|
||||
background: default_background(),
|
||||
text: default_text(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── [oem] ────────────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct OemConfig {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
#[allow(dead_code)]
|
||||
pub skip_steps: Vec<usize>,
|
||||
#[serde(default)]
|
||||
pub default_username: String,
|
||||
#[serde(default = "default_hostname")]
|
||||
pub default_hostname: String,
|
||||
#[serde(default)]
|
||||
pub default_password: String,
|
||||
}
|
||||
|
||||
// ── Varsayılan değerler ───────────────────────────────────────────────────────
|
||||
|
||||
fn default_title() -> String { "YALI Installation Tool".to_string() }
|
||||
fn default_subtitle() -> String { "PiSi GNU/LINUX".to_string() }
|
||||
fn default_yali_logo() -> String { "assets/yali.png".to_string() }
|
||||
fn default_pisi_logo_dark() -> String { "assets/pisi-logo-dark.png".to_string() }
|
||||
fn default_pisi_logo_light() -> String { "assets/pisi-logo-light.png".to_string() }
|
||||
fn default_interval() -> u64 { 6 }
|
||||
fn default_primary() -> String { "#1a73e8".to_string() }
|
||||
fn default_accent() -> String { "#34a853".to_string() }
|
||||
fn default_background() -> String { "#181824".to_string() }
|
||||
fn default_text() -> String { "#e2e8f0".to_string() }
|
||||
fn default_hostname() -> String { "pisi-oem".to_string() }
|
||||
|
||||
// ── Yükleme ──────────────────────────────────────────────────────────────────
|
||||
|
||||
impl BrandingConfig {
|
||||
/// `branding.toml` dosyasını arar ve yükler.
|
||||
///
|
||||
/// Arama sırası:
|
||||
/// 1. `/etc/yali/branding.toml`
|
||||
/// 2. `/usr/share/yali/branding.toml`
|
||||
/// 3. Çalışma dizinindeki `branding.toml`
|
||||
pub fn load() -> Self {
|
||||
let paths = [
|
||||
"/etc/yali/branding.toml",
|
||||
"/usr/share/yali/branding.toml",
|
||||
"branding.toml",
|
||||
];
|
||||
for path in &paths {
|
||||
if let Ok(content) = std::fs::read_to_string(path) {
|
||||
match toml::from_str(&content) {
|
||||
Ok(cfg) => return cfg,
|
||||
Err(e) => eprintln!("[branding] {}: {}", path, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
BrandingConfig::default()
|
||||
}
|
||||
|
||||
/// Belirtilen dile ait `branding_{lang}.toml` dosyasını arar ve yükler.
|
||||
/// Bulunamazsa varsayılan `branding.toml` dosyasına geri döner.
|
||||
pub fn load_for_lang(lang: &str) -> Self {
|
||||
let lang_paths = [
|
||||
format!("/etc/yali/branding_{}.toml", lang),
|
||||
format!("/usr/share/yali/branding_{}.toml", lang),
|
||||
format!("branding_{}.toml", lang),
|
||||
];
|
||||
for path in &lang_paths {
|
||||
if let Ok(content) = std::fs::read_to_string(path) {
|
||||
match toml::from_str(&content) {
|
||||
Ok(cfg) => return cfg,
|
||||
Err(e) => eprintln!("[branding] {}: {}", path, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::load()
|
||||
}
|
||||
|
||||
/// İkon adına göre dosya yolunu döner.
|
||||
///
|
||||
/// Koyu/açık temaya duyarlı `pisilogo` ikonu için `is_dark` parametresi
|
||||
/// kullanılır; diğer ikonlar için görmezden gelinir.
|
||||
pub fn icon_path(&self, icon: &str, is_dark: bool) -> Option<String> {
|
||||
// pisilogo özel durumu: tema bazlı iki ayrı anahtar
|
||||
if icon == "pisilogo" {
|
||||
let key = if is_dark { "pisi_logo_dark" } else { "pisi_logo_light" };
|
||||
return self.slides.icons.get(key).cloned();
|
||||
}
|
||||
self.slides.icons.get(icon).cloned()
|
||||
}
|
||||
|
||||
/// Sol kenar çubuğu (Yali) logosu için `file://` URI döner.
|
||||
pub fn yali_logo_uri(&self) -> String {
|
||||
path_to_file_uri(&self.general.yali_logo)
|
||||
}
|
||||
|
||||
/// Ana sayfa PisiLinux logosu (koyu tema) için `file://` URI döner.
|
||||
pub fn pisi_logo_dark_uri(&self) -> String {
|
||||
path_to_file_uri(&self.general.pisi_logo_dark)
|
||||
}
|
||||
|
||||
/// Ana sayfa PisiLinux logosu (açık tema) için `file://` URI döner.
|
||||
pub fn pisi_logo_light_uri(&self) -> String {
|
||||
path_to_file_uri(&self.general.pisi_logo_light)
|
||||
}
|
||||
}
|
||||
|
||||
/// Göreli veya mutlak dosya yolunu `egui::Image::from_uri` için uygun
|
||||
/// `file://` URI formatına çevirir.
|
||||
pub fn path_to_file_uri(path: &str) -> String {
|
||||
if path.starts_with("file://") || path.starts_with("http") {
|
||||
return path.to_string();
|
||||
}
|
||||
if std::path::Path::new(path).is_absolute() {
|
||||
return format!("file://{}", path);
|
||||
}
|
||||
|
||||
// Göreli yolları sırasıyla ara:
|
||||
// 1. Çalışma dizini (CWD)
|
||||
// 2. /usr/share/yali/
|
||||
// 3. /etc/yali/
|
||||
let cwd = std::env::current_dir().unwrap_or_default();
|
||||
let cwd_path = cwd.join(path);
|
||||
if cwd_path.exists() {
|
||||
return format!("file://{}", cwd_path.display());
|
||||
}
|
||||
|
||||
let usr_path = std::path::Path::new("/usr/share/yali").join(path);
|
||||
if usr_path.exists() {
|
||||
return format!("file://{}", usr_path.display());
|
||||
}
|
||||
|
||||
let etc_path = std::path::Path::new("/etc/yali").join(path);
|
||||
if etc_path.exists() {
|
||||
return format!("file://{}", etc_path.display());
|
||||
}
|
||||
|
||||
// Hiçbiri bulunamazsa varsayılan olarak CWD yolunu döner (hata/fallback takibi için)
|
||||
format!("file://{}", cwd_path.display())
|
||||
}
|
||||
+391
-27
@@ -1,4 +1,5 @@
|
||||
use eframe::egui;
|
||||
use sysinfo::System;
|
||||
use rust_i18n::t;
|
||||
|
||||
/// Disk adı ve bölüm numarasından tam aygıt yolunu oluşturur.
|
||||
@@ -45,6 +46,8 @@ pub struct PartitionPlan {
|
||||
pub efi_mb: u64, // 0 → BIOS, >0 → UEFI
|
||||
pub swap_mb: u64,
|
||||
pub root_mb: u64, // kalan alan
|
||||
pub encrypt_root: bool, // Kök bölümü LUKS ile şifrelensin mi?
|
||||
pub luks_password: String, // LUKS şifresi
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
@@ -67,23 +70,31 @@ impl std::fmt::Display for PartitionTableType {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum FsType {
|
||||
Ext4,
|
||||
Ext3,
|
||||
Btrfs,
|
||||
Xfs,
|
||||
Fat32, // EFI bölümü için
|
||||
Ntfs,
|
||||
Swap,
|
||||
Lvm, // LVM fiziksel bölüm (PV)
|
||||
#[allow(dead_code)]
|
||||
LvmLv, // LVM mantıksal bölüm (LV)
|
||||
}
|
||||
|
||||
impl FsType {
|
||||
pub fn label(&self) -> &'static str {
|
||||
match self {
|
||||
FsType::Ext4 => "ext4",
|
||||
FsType::Ext3 => "ext3",
|
||||
FsType::Btrfs => "btrfs",
|
||||
FsType::Xfs => "xfs",
|
||||
FsType::Fat32 => "FAT32 (EFI)",
|
||||
FsType::Ntfs => "NTFS",
|
||||
FsType::Swap => "swap",
|
||||
FsType::Lvm => "LVM PV",
|
||||
FsType::LvmLv => "LVM LV",
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FsType {
|
||||
@@ -92,6 +103,25 @@ impl std::fmt::Display for FsType {
|
||||
}
|
||||
}
|
||||
|
||||
/// LVM Volume Group yapılandırması.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct VolumeGroup {
|
||||
pub name: String,
|
||||
pub pv_devices: Vec<String>, // PV olarak kullanılacak bölüm aygıtları
|
||||
pub size_mb: u64, // VG toplam boyutu (hesaplanan)
|
||||
}
|
||||
|
||||
/// LVM Logical Volume yapılandırması.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LogicalVolume {
|
||||
pub name: String,
|
||||
pub vg_name: String,
|
||||
pub size_mb: u64, // 0 = kalan alan
|
||||
pub fstype: FsType,
|
||||
#[allow(dead_code)]
|
||||
pub mountpoint: String,
|
||||
}
|
||||
|
||||
/// Kullanıcının manuel olarak tanımladığı tek bir bölüm.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CustomPartition {
|
||||
@@ -103,6 +133,12 @@ pub struct CustomPartition {
|
||||
pub fstype: FsType,
|
||||
/// Bağlama noktası; swap için "swap"
|
||||
pub mountpoint: String,
|
||||
/// LUKS şifreleme aktif mi?
|
||||
pub encrypt: bool,
|
||||
/// LUKS şifresi
|
||||
pub luks_password: String,
|
||||
/// LUKS harici adı (ör. "cryptroot")
|
||||
pub luks_name: String,
|
||||
}
|
||||
|
||||
/// Kurulum boyunca toplanan tüm veriler.
|
||||
@@ -114,6 +150,8 @@ pub struct GlobalState {
|
||||
pub partition_plan: Option<PartitionPlan>,
|
||||
/// Manuel bölümleme modu için kullanıcının tanımladığı bölümler.
|
||||
pub custom_partitions: Vec<CustomPartition>,
|
||||
pub volume_groups: Vec<VolumeGroup>,
|
||||
pub logical_volumes: Vec<LogicalVolume>,
|
||||
pub keyboard_layout: String,
|
||||
pub keyboard_variant: String,
|
||||
pub username: String,
|
||||
@@ -126,6 +164,44 @@ pub struct GlobalState {
|
||||
pub install_log: Vec<String>,
|
||||
pub demo_mode: bool,
|
||||
pub is_dark: bool,
|
||||
pub rescue_mode: bool,
|
||||
pub bootloader_device: String,
|
||||
pub bootloader_timeout: u32,
|
||||
pub bootloader_password: String,
|
||||
pub kernel_options: String,
|
||||
pub license_accepted: bool,
|
||||
pub root_password: String,
|
||||
pub root_password_confirm: String,
|
||||
pub display_manager: String,
|
||||
pub autologin: bool,
|
||||
pub desktop_environment: String,
|
||||
pub network_wifi_password: String,
|
||||
pub network_http_proxy: String,
|
||||
pub network_https_proxy: String,
|
||||
pub network_ftp_proxy: String,
|
||||
pub use_ntp: bool,
|
||||
pub manual_year: i32,
|
||||
pub manual_month: u32,
|
||||
pub manual_day: u32,
|
||||
pub manual_hour: u32,
|
||||
pub manual_minute: u32,
|
||||
#[allow(dead_code)]
|
||||
pub encrypt_root: bool,
|
||||
#[allow(dead_code)]
|
||||
pub luks_password: String,
|
||||
pub oem_mode: bool,
|
||||
pub selected_package_groups: Vec<String>,
|
||||
/// branding.toml [slides.icons] tablosundan yüklenen ikon → dosya URI eşlemesi.
|
||||
/// Slideshow bu map üzerinden çalışma zamanında görsel yollarını çözümler.
|
||||
pub branding_icons: std::collections::HashMap<String, String>,
|
||||
/// Sidebar için koyu tema logo URI'si.
|
||||
pub branding_yali_dark: String,
|
||||
pub branding_pisi_dark: String,
|
||||
/// Sidebar için açık tema logo URI'si.
|
||||
pub branding_yali_light: String,
|
||||
pub branding_pisi_light: String,
|
||||
/// branding.toml dosyasından yüklenen slaytlar.
|
||||
pub branding_slides: Vec<crate::branding::SlideItem>,
|
||||
}
|
||||
|
||||
impl Default for GlobalState {
|
||||
@@ -137,6 +213,8 @@ impl Default for GlobalState {
|
||||
erase_disk: true,
|
||||
partition_plan: None,
|
||||
custom_partitions: Vec::new(),
|
||||
volume_groups: Vec::new(),
|
||||
logical_volumes: Vec::new(),
|
||||
keyboard_layout: "tr".to_string(),
|
||||
keyboard_variant: String::new(),
|
||||
username: String::new(),
|
||||
@@ -149,11 +227,51 @@ impl Default for GlobalState {
|
||||
install_log: Vec::new(),
|
||||
demo_mode: false,
|
||||
is_dark: true,
|
||||
rescue_mode: false,
|
||||
bootloader_device: String::new(),
|
||||
bootloader_timeout: 5,
|
||||
bootloader_password: String::new(),
|
||||
kernel_options: String::new(),
|
||||
license_accepted: false,
|
||||
root_password: String::new(),
|
||||
root_password_confirm: String::new(),
|
||||
network_wifi_password: String::new(),
|
||||
network_http_proxy: String::new(),
|
||||
network_https_proxy: String::new(),
|
||||
network_ftp_proxy: String::new(),
|
||||
use_ntp: true,
|
||||
manual_year: 2026,
|
||||
manual_month: 5,
|
||||
manual_day: 26,
|
||||
manual_hour: 12,
|
||||
manual_minute: 0,
|
||||
encrypt_root: false,
|
||||
luks_password: String::new(),
|
||||
oem_mode: false,
|
||||
selected_package_groups: Vec::new(),
|
||||
display_manager: "sddm".to_string(),
|
||||
autologin: true,
|
||||
desktop_environment: {
|
||||
let de = std::env::var("XDG_CURRENT_DESKTOP")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_lowercase();
|
||||
if de.is_empty() {
|
||||
"plasma".to_string()
|
||||
} else {
|
||||
de
|
||||
}
|
||||
},
|
||||
branding_icons: std::collections::HashMap::new(),
|
||||
branding_pisi_dark: String::new(),
|
||||
branding_pisi_light: String::new(),
|
||||
branding_yali_dark: String::new(),
|
||||
branding_yali_light: String::new(),
|
||||
branding_slides: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// WELCOME STEP (sistem gereksinimleri + dil seçimi)
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
@@ -167,7 +285,11 @@ pub struct WelcomeStep {
|
||||
|
||||
impl Default for WelcomeStep {
|
||||
fn default() -> Self {
|
||||
Self { checks: Vec::new(), checked: false, last_language: String::new() }
|
||||
Self {
|
||||
checks: Vec::new(),
|
||||
checked: false,
|
||||
last_language: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,12 +315,54 @@ impl InstallerStep for WelcomeStep {
|
||||
}
|
||||
|
||||
theme::section_heading(ui, &t!("welcome_title"));
|
||||
ui.label(
|
||||
|
||||
ui.label(
|
||||
egui::RichText::new(t!("welcome_description"))
|
||||
.color(theme::c_text_dim())
|
||||
.size(13.0),
|
||||
.size(15.0),
|
||||
);
|
||||
|
||||
ui.add_space(16.0);
|
||||
|
||||
ui.vertical_centered(|ui| {
|
||||
let logo_uri = if state.is_dark {
|
||||
&state.branding_pisi_dark
|
||||
} else {
|
||||
&state.branding_pisi_light
|
||||
};
|
||||
if !logo_uri.is_empty() {
|
||||
ui.add(
|
||||
egui::Image::from_uri(logo_uri.as_str())
|
||||
.max_width(120.0)
|
||||
.rounding(egui::Rounding::same(8.0)),
|
||||
);
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
let os_name = System::name().unwrap_or_else(|| "Bilinmiyor".to_string());
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{} : {}", t!("os"), os_name))
|
||||
.strong()
|
||||
.size(16.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
ui.add_space(4.0);
|
||||
let os_version = System::os_version().unwrap_or_else(|| "Bilinmiyor".to_string());
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{} : {}", t!("version"), os_version))
|
||||
.size(14.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
|
||||
let desktop_name = std::env::var("XDG_CURRENT_DESKTOP").unwrap_or_default();
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{} : {}", t!("desktop"), desktop_name))
|
||||
.size(14.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
ui.add_space(12.0);
|
||||
|
||||
// Dil seçimi (Açılır Liste / ComboBox)
|
||||
@@ -232,7 +396,6 @@ impl InstallerStep for WelcomeStep {
|
||||
.striped(true)
|
||||
.show(ui, |ui| {
|
||||
for check in &self.checks {
|
||||
// Durum simgesi + renk
|
||||
let (icon, color) = match check.status {
|
||||
CheckStatus::Pass => ("✅", theme::c_success()),
|
||||
CheckStatus::Warn => ("⚠️", theme::c_warning()),
|
||||
@@ -249,6 +412,27 @@ impl InstallerStep for WelcomeStep {
|
||||
}
|
||||
});
|
||||
|
||||
// Rescue mode butonu
|
||||
ui.add_space(10.0);
|
||||
ui.horizontal(|ui| {
|
||||
let rescue_available = detect_existing_linux();
|
||||
if rescue_available {
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(80, 170, 80),
|
||||
"🛟",
|
||||
);
|
||||
if ui.add(theme::secondary_button(&t!("rescue_button"))).clicked() {
|
||||
state.rescue_mode = true;
|
||||
}
|
||||
} else {
|
||||
ui.label(
|
||||
egui::RichText::new(t!("rescue_not_available"))
|
||||
.size(12.0)
|
||||
.color(egui::Color32::from_rgb(120, 120, 140)),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Hata varsa uyarı
|
||||
ui.add_space(10.0);
|
||||
let has_fail = self.checks.iter().any(|c| c.status == CheckStatus::Fail);
|
||||
@@ -269,11 +453,9 @@ impl InstallerStep for WelcomeStep {
|
||||
}
|
||||
|
||||
fn is_complete(&self, state: &GlobalState) -> bool {
|
||||
// Demo modunda her zaman ileri gitmeye izin ver
|
||||
if state.demo_mode {
|
||||
return true;
|
||||
}
|
||||
// Fail varsa ilerleyemez; kontroller bitmemişse de bekle
|
||||
!self.checks.is_empty() && all_passed(&self.checks)
|
||||
}
|
||||
}
|
||||
@@ -283,8 +465,9 @@ impl InstallerStep for WelcomeStep {
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
pub struct LocationStep {
|
||||
search_query: String,
|
||||
timezones: Vec<String>,
|
||||
geoip_done: bool,
|
||||
datetime_init_done: bool,
|
||||
}
|
||||
|
||||
impl Default for LocationStep {
|
||||
@@ -296,29 +479,210 @@ impl Default for LocationStep {
|
||||
"Europe/London", "Europe/Moscow", "Europe/Paris", "Europe/Rome",
|
||||
"Pacific/Auckland",
|
||||
].iter().map(|s| s.to_string()).collect();
|
||||
Self { search_query: String::new(), timezones: tz_list }
|
||||
Self {
|
||||
timezones: tz_list,
|
||||
geoip_done: false,
|
||||
datetime_init_done: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LocationStep {
|
||||
fn geoip_lookup(state: &mut GlobalState) {
|
||||
let out = std::process::Command::new("curl")
|
||||
.args(["-s", "--connect-timeout", "3", "http://ip-api.com/json"])
|
||||
.output();
|
||||
if let Ok(o) = out {
|
||||
if let Ok(text) = String::from_utf8(o.stdout) {
|
||||
let extract = |key: &str| -> Option<String> {
|
||||
let pat = format!("\"{}\":\"", key);
|
||||
text.find(&pat).and_then(|pos| {
|
||||
let start = pos + pat.len();
|
||||
text[start..].find('"').map(|end| text[start..start+end].to_string())
|
||||
})
|
||||
};
|
||||
if let Some(country) = extract("countryCode") {
|
||||
match country.as_str() {
|
||||
"TR" => state.language = "tr".to_string(),
|
||||
"DE" => state.language = "de".to_string(),
|
||||
"FR" => state.language = "fr".to_string(),
|
||||
"IT" => state.language = "it".to_string(),
|
||||
"ES" => state.language = "es".to_string(),
|
||||
"RU" => state.language = "ru".to_string(),
|
||||
"NL" => state.language = "nl".to_string(),
|
||||
"PL" => state.language = "pl".to_string(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if let Some(tz) = extract("timezone") {
|
||||
if !tz.is_empty() {
|
||||
state.timezone = tz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_from_system(&mut self, state: &mut GlobalState) {
|
||||
use chrono::{Datelike, Timelike};
|
||||
let now_str = chrono::Local::now().format("%Y-%m-%d %H:%M").to_string();
|
||||
if let Ok(dt) = chrono::NaiveDateTime::parse_from_str(&now_str, "%Y-%m-%d %H:%M") {
|
||||
state.manual_year = dt.year();
|
||||
state.manual_month = dt.month();
|
||||
state.manual_day = dt.day();
|
||||
state.manual_hour = dt.hour();
|
||||
state.manual_minute = dt.minute();
|
||||
}
|
||||
self.datetime_init_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl InstallerStep for LocationStep {
|
||||
fn name(&self) -> String { t!("location").to_string() }
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.heading(t!("location_title"));
|
||||
ui.label(t!("location_description"));
|
||||
ui.add_space(10.0);
|
||||
ui.label(t!("search_timezone"));
|
||||
ui.text_edit_singleline(&mut self.search_query);
|
||||
ui.add_space(5.0);
|
||||
egui::ScrollArea::vertical().max_height(300.0).show(ui, |ui| {
|
||||
for tz in &self.timezones {
|
||||
if tz.to_lowercase().contains(&self.search_query.to_lowercase()) {
|
||||
ui.selectable_value(&mut state.timezone, tz.clone(), tz);
|
||||
}
|
||||
}
|
||||
});
|
||||
fn name(&self) -> String {
|
||||
format!("{} / {}", t!("location"), t!("datetime"))
|
||||
}
|
||||
|
||||
fn is_complete(&self, state: &GlobalState) -> bool { !state.timezone.is_empty() }
|
||||
fn on_enter(&mut self, state: &mut GlobalState) {
|
||||
if !self.geoip_done {
|
||||
Self::geoip_lookup(state);
|
||||
self.geoip_done = true;
|
||||
}
|
||||
if !self.datetime_init_done {
|
||||
self.init_from_system(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
use crate::ui::theme;
|
||||
|
||||
// --- BÖLGE VE ZAMAN DİLİMİ (Region & Timezone) ---
|
||||
theme::section_heading(ui, &t!("location_title"));
|
||||
ui.label(
|
||||
egui::RichText::new(t!("location_description"))
|
||||
.color(theme::c_text_dim())
|
||||
.size(13.0),
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new(t!("location_title")).strong().color(theme::c_text()));
|
||||
|
||||
let current_tz = if state.timezone.is_empty() {
|
||||
"Europe/Istanbul".to_string()
|
||||
} else {
|
||||
state.timezone.clone()
|
||||
};
|
||||
if state.timezone.is_empty() {
|
||||
state.timezone = current_tz.clone();
|
||||
}
|
||||
|
||||
egui::ComboBox::from_id_source("timezone_select")
|
||||
.selected_text(¤t_tz)
|
||||
.width(280.0)
|
||||
.show_ui(ui, |ui| {
|
||||
for tz in &self.timezones {
|
||||
ui.selectable_value(&mut state.timezone, tz.clone(), tz);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(16.0);
|
||||
ui.separator();
|
||||
ui.add_space(16.0);
|
||||
|
||||
// --- TARİH VE SAAT AYARLARI (Date & Time) ---
|
||||
theme::section_heading(ui, &t!("datetime_title"));
|
||||
ui.label(
|
||||
egui::RichText::new(t!("datetime_description"))
|
||||
.color(theme::c_text_dim())
|
||||
.size(13.0),
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
|
||||
egui::Frame::group(ui.style())
|
||||
.fill(theme::c_bg_widget())
|
||||
.rounding(6.0)
|
||||
.inner_margin(egui::Margin::same(12.0))
|
||||
.show(ui, |ui| {
|
||||
ui.set_width(ui.available_width());
|
||||
egui::Grid::new("datetime_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 10.0])
|
||||
.show(ui, |ui| {
|
||||
// NTP
|
||||
ui.label(egui::RichText::new(t!("datetime_ntp_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(egui::Checkbox::new(&mut state.use_ntp, ""));
|
||||
let status = if state.use_ntp { t!("datetime_ntp_on") } else { t!("datetime_ntp_off") };
|
||||
ui.colored_label(
|
||||
if state.use_ntp { theme::c_success() } else { theme::c_error() },
|
||||
status,
|
||||
);
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
if !state.use_ntp {
|
||||
// Tarih
|
||||
ui.label(egui::RichText::new(t!("datetime_date_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(t!("datetime_year"));
|
||||
ui.add(egui::DragValue::new(&mut state.manual_year).clamp_range(2000..=2100).speed(1));
|
||||
ui.label(t!("datetime_month"));
|
||||
ui.add(egui::DragValue::new(&mut state.manual_month).clamp_range(1..=12).speed(1));
|
||||
ui.label(t!("datetime_day"));
|
||||
ui.add(egui::DragValue::new(&mut state.manual_day).clamp_range(1..=31).speed(1));
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Saat
|
||||
ui.label(egui::RichText::new(t!("datetime_time_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(egui::DragValue::new(&mut state.manual_hour).clamp_range(0..=23).speed(1));
|
||||
ui.label(":");
|
||||
ui.add(egui::DragValue::new(&mut state.manual_minute).clamp_range(0..=59).speed(1));
|
||||
});
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(8.0);
|
||||
if state.use_ntp {
|
||||
ui.label(
|
||||
egui::RichText::new(t!("datetime_ntp_info"))
|
||||
.size(11.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
} else {
|
||||
ui.label(
|
||||
egui::RichText::new(t!("datetime_manual_info"))
|
||||
.size(11.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_complete(&self, state: &GlobalState) -> bool {
|
||||
!state.timezone.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// Mevcut bir Linux kurulumu olup olmadığını kontrol eder.
|
||||
/// Basitçe /mnt/etc/fstab varlığına veya blkid ile Linux bölümlerine bakar.
|
||||
fn detect_existing_linux() -> bool {
|
||||
// /etc/fstab veya /mnt/etc/fstab kontrolü
|
||||
if std::path::Path::new("/mnt/etc/fstab").exists() {
|
||||
return true;
|
||||
}
|
||||
// blkid ile Linux bölümlerini tara
|
||||
if let Ok(out) = std::process::Command::new("blkid")
|
||||
.args(["-o", "list"])
|
||||
.output()
|
||||
{
|
||||
let text = String::from_utf8_lossy(&out.stdout);
|
||||
text.lines().any(|l| l.contains("ext4") || l.contains("btrfs") || l.contains("xfs"))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+971
-205
File diff suppressed because it is too large
Load Diff
+140
-59
@@ -3,9 +3,10 @@ mod steps;
|
||||
mod jobs;
|
||||
mod ui;
|
||||
mod autoinstall;
|
||||
mod branding;
|
||||
|
||||
use installer::{GlobalState, InstallerStep, WelcomeStep, LocationStep};
|
||||
use steps::{KeyboardStep, UsersStep, SummaryStep, ExecutionStep, FinishStep, PartitionStep};
|
||||
use steps::{KeyboardStep, UsersStep, SummaryStep, ExecutionStep, FinishStep, PartitionStep, BootloaderStep, LicenseStep, NetworkStep, DisplayManagerStep};
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
|
||||
@@ -32,14 +33,14 @@ fn main() -> eframe::Result<()> {
|
||||
fn run_gui(demo_mode: bool) -> eframe::Result<()> {
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_inner_size([1100.0, 760.0])
|
||||
.with_min_inner_size([900.0, 650.0])
|
||||
.with_title(t!("installer").to_string()),
|
||||
.with_inner_size([1200.0, 900.0])
|
||||
.with_min_inner_size([1080.0, 720.0])
|
||||
.with_title(t!("installer")),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
&t!("installer").to_string(),
|
||||
t!("installer").as_ref(),
|
||||
options,
|
||||
Box::new(move |cc| {
|
||||
// Görsel yükleyicileri etkinleştir (PNG desteği)
|
||||
@@ -88,17 +89,19 @@ fn run_auto_install(path: &str, demo_mode: bool) -> eframe::Result<()> {
|
||||
}
|
||||
|
||||
if !autoinstall::checker::all_passed(&checks) {
|
||||
eprintln!("{}: {}", t!("error"), "Critical check error. Installation stopped.");
|
||||
eprintln!("{}: Critical check error. Installation stopped.", t!("error"));
|
||||
std::process::exit(2);
|
||||
}
|
||||
|
||||
// State'i hazırla
|
||||
let mut state = GlobalState::default();
|
||||
state.demo_mode = demo_mode;
|
||||
let mut state = GlobalState {
|
||||
demo_mode,
|
||||
..Default::default()
|
||||
};
|
||||
apply_to_state(&af, &mut state);
|
||||
|
||||
if state.partition_plan.is_none() {
|
||||
eprintln!("{}: {}", t!("error"), format!("{}: {}", t!("partition_plan_could_not_be_created"), af.install.disk));
|
||||
eprintln!("{}: {}: {}", t!("error"), t!("partition_plan_could_not_be_created"), af.install.disk);
|
||||
std::process::exit(3);
|
||||
}
|
||||
|
||||
@@ -122,13 +125,9 @@ fn run_auto_install(path: &str, demo_mode: bool) -> eframe::Result<()> {
|
||||
use jobs::{InstallMessage, UiSender};
|
||||
|
||||
// CLI modunda egui Context yok; basit bir mpsc kanal kullanıyoruz.
|
||||
// UiSender'a dummy bir context gerekeceğinden terminal çıktısı için
|
||||
// doğrudan kanalı dinliyoruz.
|
||||
let (tx, rx) = mpsc::channel::<InstallMessage>();
|
||||
|
||||
// Arka plan iş parçacığı — gerçek job kuyruğunu çalıştırır.
|
||||
// egui::Context::default() CLI modunda request_repaint()'i no-op yapar;
|
||||
// mesajlar mpsc kanalı üzerinden terminale aktarılır.
|
||||
let cli_ctx = eframe::egui::Context::default();
|
||||
let ui_sender = UiSender::new(tx, cli_ctx);
|
||||
|
||||
@@ -147,16 +146,33 @@ fn run_auto_install(path: &str, demo_mode: bool) -> eframe::Result<()> {
|
||||
let rt = tokio::runtime::Runtime::new().expect("tokio runtime");
|
||||
let mut queue = jobs::build_full_job_queue(
|
||||
plan_c,
|
||||
&mount_c,
|
||||
&source_c,
|
||||
&locale_c,
|
||||
&timezone_c,
|
||||
&username_c,
|
||||
&password_c,
|
||||
&hostname_c,
|
||||
&kb_layout_c,
|
||||
&kb_variant_c,
|
||||
demo_mode,
|
||||
jobs::JobQueueConfig {
|
||||
mount: mount_c,
|
||||
source: source_c,
|
||||
locale: locale_c,
|
||||
timezone: timezone_c,
|
||||
username: username_c,
|
||||
password: password_c,
|
||||
hostname: hostname_c,
|
||||
kb_layout: kb_layout_c,
|
||||
kb_variant: kb_variant_c,
|
||||
demo_mode,
|
||||
boot_device: String::new(),
|
||||
bootloader_timeout: 5,
|
||||
bootloader_password: String::new(),
|
||||
kernel_options: String::new(),
|
||||
use_ntp: true,
|
||||
root_password: String::new(),
|
||||
display_manager: "sddm".to_string(),
|
||||
autologin: true,
|
||||
desktop_environment: "plasma".to_string(),
|
||||
selected_package_groups: Vec::new(),
|
||||
manual_year: 2026,
|
||||
manual_month: 5,
|
||||
manual_day: 26,
|
||||
manual_hour: 12,
|
||||
manual_minute: 0,
|
||||
},
|
||||
);
|
||||
rt.block_on(queue.run_all(ui_sender));
|
||||
});
|
||||
@@ -182,32 +198,69 @@ fn run_auto_install(path: &str, demo_mode: bool) -> eframe::Result<()> {
|
||||
}
|
||||
});
|
||||
|
||||
// eframe::Result döndürmek için Ok
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct YaliApp {
|
||||
state: GlobalState,
|
||||
steps: Vec<Box<dyn InstallerStep>>,
|
||||
last_step: usize,
|
||||
state: GlobalState,
|
||||
steps: Vec<Box<dyn InstallerStep>>,
|
||||
rescue_step: Option<Box<dyn InstallerStep>>,
|
||||
last_step: usize,
|
||||
branding: branding::BrandingConfig,
|
||||
loaded_language: String,
|
||||
}
|
||||
|
||||
impl Default for YaliApp {
|
||||
fn default() -> Self {
|
||||
let default_lang = "tr".to_string();
|
||||
let branding = branding::BrandingConfig::load_for_lang(&default_lang);
|
||||
let mut app = Self {
|
||||
state: GlobalState::default(),
|
||||
steps: vec![
|
||||
Box::new(WelcomeStep::default()),
|
||||
Box::new(LocationStep::default()),
|
||||
Box::new(LicenseStep),
|
||||
Box::new(KeyboardStep::default()),
|
||||
Box::new(NetworkStep::default()),
|
||||
Box::new(PartitionStep::default()),
|
||||
Box::new(UsersStep::default()),
|
||||
Box::new(BootloaderStep::default()),
|
||||
Box::new(DisplayManagerStep::default()),
|
||||
Box::new(SummaryStep),
|
||||
Box::new(ExecutionStep::default()),
|
||||
Box::new(FinishStep),
|
||||
],
|
||||
rescue_step: Some(Box::new(steps::RescueStep::default())),
|
||||
last_step: usize::MAX,
|
||||
branding: branding.clone(),
|
||||
loaded_language: String::new(),
|
||||
};
|
||||
|
||||
// OEM modu: varsayılan değerleri ata ve step engelleme
|
||||
if branding.oem.enabled {
|
||||
app.state.oem_mode = true;
|
||||
if !branding.oem.default_username.is_empty() {
|
||||
app.state.username = branding.oem.default_username.clone();
|
||||
app.state.hostname = branding.oem.default_hostname.clone();
|
||||
}
|
||||
if !branding.oem.default_password.is_empty() {
|
||||
app.state.password = branding.oem.default_password.clone();
|
||||
app.state.password_confirm = branding.oem.default_password.clone();
|
||||
}
|
||||
// OEM ön tanımlı disk planı varsa?
|
||||
}
|
||||
|
||||
// Branding görsel verilerini GlobalState'e enjekte et
|
||||
app.state.branding_yali_dark = branding.yali_logo_uri();
|
||||
app.state.branding_yali_light = branding.yali_logo_uri();
|
||||
app.state.branding_pisi_dark = branding.pisi_logo_dark_uri();
|
||||
app.state.branding_pisi_light = branding.pisi_logo_light_uri();
|
||||
app.state.branding_icons = branding.slides.icons
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), branding::path_to_file_uri(v)))
|
||||
.collect();
|
||||
app.state.branding_slides = branding.slides.items.clone();
|
||||
|
||||
app.steps[0].on_enter(&mut app.state);
|
||||
app.last_step = 0;
|
||||
app
|
||||
@@ -218,6 +271,45 @@ impl eframe::App for YaliApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
rust_i18n::set_locale(&self.state.language);
|
||||
|
||||
// Dil değişimi kontrolü -> branding dosyasını dinamik olarak yeniden yükle
|
||||
if self.loaded_language != self.state.language {
|
||||
self.loaded_language = self.state.language.clone();
|
||||
let branding = branding::BrandingConfig::load_for_lang(&self.loaded_language);
|
||||
self.branding = branding.clone();
|
||||
self.state.branding_yali_dark = branding.yali_logo_uri();
|
||||
self.state.branding_yali_light = branding.yali_logo_uri();
|
||||
self.state.branding_pisi_dark = branding.pisi_logo_dark_uri();
|
||||
self.state.branding_pisi_light = branding.pisi_logo_light_uri();
|
||||
self.state.branding_icons = branding.slides.icons
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), branding::path_to_file_uri(v)))
|
||||
.collect();
|
||||
self.state.branding_slides = branding.slides.items.clone();
|
||||
|
||||
// Pencere başlığını dinamik olarak güncelle
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Title(self.branding.general.title.clone()));
|
||||
}
|
||||
|
||||
// Rescue modu: tam ekran, sidebar yok, navigasyon yok
|
||||
if self.state.rescue_mode {
|
||||
if let Some(rescue) = &mut self.rescue_step {
|
||||
egui::CentralPanel::default()
|
||||
.frame(egui::Frame::none()
|
||||
.fill(ui::theme::c_bg_dark())
|
||||
.inner_margin(egui::Margin::same(20.0)))
|
||||
.show(ctx, |ui| {
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
rescue.show(ui, &mut self.state);
|
||||
});
|
||||
ui.add_space(12.0);
|
||||
if ui.button(t!("rescue_return")).clicked() {
|
||||
self.state.rescue_mode = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let cur = self.state.current_step;
|
||||
let n_steps = self.steps.len();
|
||||
let is_exec = cur == n_steps - 2;
|
||||
@@ -238,31 +330,31 @@ impl eframe::App for YaliApp {
|
||||
.show(ctx, |ui| {
|
||||
ui.add_space(20.0);
|
||||
|
||||
// PisiLinux logo
|
||||
// Dağıtım logosu — branding.toml'dan dinamik yüklenir
|
||||
ui.vertical_centered(|ui| {
|
||||
let logo = if self.state.is_dark {
|
||||
egui::include_image!("../assets/pisi-logo-dark.png")
|
||||
let logo_uri = if self.state.is_dark {
|
||||
&self.state.branding_yali_dark
|
||||
} else {
|
||||
egui::include_image!("../assets/pisi-logo-light.png")
|
||||
&self.state.branding_yali_light
|
||||
};
|
||||
ui.add(
|
||||
egui::Image::new(logo)
|
||||
.max_width(120.0)
|
||||
.rounding(egui::Rounding::same(8.0)),
|
||||
);
|
||||
if !logo_uri.is_empty() {
|
||||
ui.add(
|
||||
egui::Image::from_uri(logo_uri.as_str())
|
||||
.max_width(120.0)
|
||||
.rounding(egui::Rounding::same(8.0)),
|
||||
);
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
ui.label(
|
||||
egui::RichText::new(t!("os_name"))
|
||||
egui::RichText::new(t!("app_name"))
|
||||
.strong()
|
||||
.size(16.0)
|
||||
.color(ui::theme::c_text_dim()),
|
||||
);
|
||||
// get desktop environment
|
||||
let desktop = std::env::var("XDG_CURRENT_DESKTOP").unwrap_or_default();
|
||||
ui.label(
|
||||
egui::RichText::new(&format!("{} Desktop", desktop))
|
||||
.size(14.0)
|
||||
.color(ui::theme::c_text_dim()),
|
||||
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(60, 60, 90),
|
||||
format!("{}: {}", t!("version"), env!("CARGO_PKG_VERSION")),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -305,15 +397,10 @@ impl eframe::App for YaliApp {
|
||||
ui.add_space(2.0);
|
||||
}
|
||||
|
||||
// Alt kısım: tema değiştirme + sürüm bilgisi
|
||||
// Alt kısım: tema değiştirme
|
||||
ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| {
|
||||
ui.add_space(12.0);
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(60, 60, 90),
|
||||
format!("YALI (v{})", env!("CARGO_PKG_VERSION")),
|
||||
);
|
||||
ui.add_space(6.0);
|
||||
// Tema değiştirme butonu
|
||||
|
||||
let theme_icon = if self.state.is_dark { "☀" } else { "🌙" };
|
||||
let theme_label = if self.state.is_dark { "Light" } else { "Dark" };
|
||||
if ui.add(
|
||||
@@ -341,11 +428,8 @@ impl eframe::App for YaliApp {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(8.0);
|
||||
|
||||
// İptal — kurulum ve bitiş ekranında gizle
|
||||
if !is_exec && !is_finish {
|
||||
if ui.add(ui::theme::secondary_button(&t!("cancel"))).clicked() {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
}
|
||||
if !is_exec && !is_finish && ui.add(ui::theme::secondary_button(&t!("cancel"))).clicked() {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
}
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
@@ -357,7 +441,6 @@ impl eframe::App for YaliApp {
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_finish {
|
||||
// İleri / Tamamlandı butonu
|
||||
if !is_exec || is_valid {
|
||||
let next_label = if is_exec {
|
||||
t!("finish_next")
|
||||
@@ -367,7 +450,6 @@ impl eframe::App for YaliApp {
|
||||
let btn = if is_valid {
|
||||
ui::theme::primary_button(&next_label)
|
||||
} else {
|
||||
// Devre dışı görünüm için secondary kullan
|
||||
ui::theme::secondary_button(&next_label)
|
||||
};
|
||||
if ui.add_enabled(is_valid, btn).clicked() {
|
||||
@@ -375,7 +457,6 @@ impl eframe::App for YaliApp {
|
||||
}
|
||||
}
|
||||
|
||||
// Geri — kurulum ekranında gizle
|
||||
if cur > 0 && !is_exec {
|
||||
ui.add_space(8.0);
|
||||
if ui.add(ui::theme::secondary_button(&t!("back"))).clicked() {
|
||||
@@ -403,4 +484,4 @@ impl eframe::App for YaliApp {
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::installer::{GlobalState, InstallerStep};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BootloaderStep {
|
||||
show_password: bool,
|
||||
timeout_str: String,
|
||||
}
|
||||
|
||||
impl InstallerStep for BootloaderStep {
|
||||
fn name(&self) -> String {
|
||||
t!("bootloader").to_string()
|
||||
}
|
||||
|
||||
fn on_enter(&mut self, state: &mut GlobalState) {
|
||||
if self.timeout_str.is_empty() {
|
||||
self.timeout_str = state.bootloader_timeout.to_string();
|
||||
}
|
||||
if state.bootloader_device.is_empty() {
|
||||
if let Some(ref disk) = state.selected_disk {
|
||||
state.bootloader_device = disk.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.heading(t!("bootloader_title"));
|
||||
ui.label(t!("bootloader_description"));
|
||||
ui.add_space(12.0);
|
||||
|
||||
egui::Grid::new("bootloader_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 10.0])
|
||||
.show(ui, |ui| {
|
||||
// Hedef aygıt
|
||||
ui.label(t!("bootloader_device_label"));
|
||||
ui.horizontal(|ui| {
|
||||
let mut device_list: Vec<String> = state.available_disks.iter()
|
||||
.map(|d| d.name.clone())
|
||||
.collect();
|
||||
if device_list.is_empty() {
|
||||
device_list.push(state.bootloader_device.clone());
|
||||
}
|
||||
let current = if state.bootloader_device.is_empty() {
|
||||
device_list[0].clone()
|
||||
} else {
|
||||
state.bootloader_device.clone()
|
||||
};
|
||||
egui::ComboBox::from_id_source("boot_device_select")
|
||||
.selected_text(¤t)
|
||||
.show_ui(ui, |ui| {
|
||||
for dev in &device_list {
|
||||
ui.selectable_value(
|
||||
&mut state.bootloader_device,
|
||||
dev.clone(),
|
||||
dev,
|
||||
);
|
||||
}
|
||||
});
|
||||
ui.label(
|
||||
egui::RichText::new(t!("bootloader_device_hint"))
|
||||
.size(11.0)
|
||||
.color(egui::Color32::from_rgb(120, 120, 140)),
|
||||
);
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Timeout
|
||||
ui.label(t!("bootloader_timeout_label"));
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(egui::Slider::new(&mut state.bootloader_timeout, 0..=60)
|
||||
.text(t!("bootloader_timeout_suffix")));
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// GRUB şifresi
|
||||
ui.label(t!("bootloader_password_label"));
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_password {
|
||||
ui.text_edit_singleline(&mut state.bootloader_password);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.bootloader_password).password(true));
|
||||
}
|
||||
if ui.small_button(if self.show_password { "🙈" } else { "👁" }).clicked() {
|
||||
self.show_password = !self.show_password;
|
||||
}
|
||||
if !state.bootloader_password.is_empty() {
|
||||
ui.colored_label(egui::Color32::from_rgb(200, 180, 40), "⚠");
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Kernel parametreleri
|
||||
ui.label(t!("bootloader_kernel_label"));
|
||||
ui.horizontal(|ui| {
|
||||
ui.text_edit_singleline(&mut state.kernel_options);
|
||||
ui.label(
|
||||
egui::RichText::new(t!("bootloader_kernel_hint"))
|
||||
.size(11.0)
|
||||
.color(egui::Color32::from_rgb(120, 120, 140)),
|
||||
);
|
||||
});
|
||||
ui.end_row();
|
||||
});
|
||||
}
|
||||
|
||||
fn is_complete(&self, state: &GlobalState) -> bool {
|
||||
!state.bootloader_device.is_empty()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::installer::{GlobalState, InstallerStep};
|
||||
|
||||
const DM_OPTIONS: &[&str] = &["sddm", "lightdm", "gdm"];
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DisplayManagerStep;
|
||||
|
||||
impl InstallerStep for DisplayManagerStep {
|
||||
fn name(&self) -> String {
|
||||
t!("display_manager").to_string()
|
||||
}
|
||||
|
||||
fn on_enter(&mut self, state: &mut GlobalState) {
|
||||
let desktop = std::env::var("XDG_CURRENT_DESKTOP")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_lowercase();
|
||||
if !desktop.is_empty() {
|
||||
state.desktop_environment = desktop;
|
||||
} else if state.desktop_environment.is_empty() {
|
||||
state.desktop_environment = "plasma".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.heading(t!("display_manager_title"));
|
||||
ui.label(t!("display_manager_description"));
|
||||
ui.add_space(12.0);
|
||||
|
||||
egui::Grid::new("dm_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 10.0])
|
||||
.show(ui, |ui| {
|
||||
// Ekran yöneticisi
|
||||
ui.label(t!("display_manager_select"));
|
||||
egui::ComboBox::from_id_source("dm_combo")
|
||||
.selected_text(state.display_manager.as_str())
|
||||
.show_ui(ui, |ui| {
|
||||
for dm in DM_OPTIONS {
|
||||
ui.selectable_value(
|
||||
&mut state.display_manager,
|
||||
dm.to_string(),
|
||||
*dm,
|
||||
);
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Masaüstü ortamı (otomatik algılanır)
|
||||
ui.label(t!("display_manager_de"));
|
||||
if !state.desktop_environment.is_empty() && state.desktop_environment != "default" {
|
||||
ui.colored_label(egui::Color32::from_rgb(120, 180, 120), &state.desktop_environment);
|
||||
} else {
|
||||
ui.colored_label(egui::Color32::from_rgb(200, 160, 40), t!("display_manager_de_not_found"));
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
// Otomatik oturum açma
|
||||
ui.label(t!("display_manager_autologin"));
|
||||
ui.checkbox(&mut state.autologin, "");
|
||||
ui.end_row();
|
||||
|
||||
if state.autologin {
|
||||
ui.label(t!("display_manager_autologin_user"));
|
||||
ui.horizontal(|ui| {
|
||||
let name = if !state.username.is_empty() {
|
||||
state.username.clone()
|
||||
} else {
|
||||
t!("display_manager_autologin_hint").to_string()
|
||||
};
|
||||
ui.colored_label(egui::Color32::from_rgb(120, 180, 120), name);
|
||||
});
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.label(egui::RichText::new(t!("display_manager_note")).size(11.0).color(egui::Color32::from_rgb(140, 140, 160)));
|
||||
}
|
||||
|
||||
fn is_complete(&self, _state: &GlobalState) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
+80
-26
@@ -15,6 +15,7 @@ use crate::jobs::{self, InstallMessage, UiSender};
|
||||
use crate::ui::{ErrorScreen, Slideshow};
|
||||
use crate::ui::theme;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ExecutionStep {
|
||||
rx: Option<mpsc::Receiver<InstallMessage>>,
|
||||
tx: Option<mpsc::Sender<InstallMessage>>,
|
||||
@@ -23,18 +24,6 @@ pub struct ExecutionStep {
|
||||
slideshow: Option<Slideshow>,
|
||||
}
|
||||
|
||||
impl Default for ExecutionStep {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
rx: None,
|
||||
tx: None,
|
||||
finished: false,
|
||||
error_screen: None,
|
||||
slideshow: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstallerStep for ExecutionStep {
|
||||
fn name(&self) -> String { t!("execution").to_string() }
|
||||
|
||||
@@ -48,7 +37,7 @@ impl InstallerStep for ExecutionStep {
|
||||
let desktop = std::env::var("XDG_CURRENT_DESKTOP")
|
||||
.unwrap_or_else(|_| "default".to_string())
|
||||
.to_lowercase();
|
||||
self.slideshow = Some(Slideshow::new(&desktop));
|
||||
self.slideshow = Some(Slideshow::new(&desktop, state.branding_icons.clone(), state.branding_slides.clone()));
|
||||
|
||||
state.install_progress = 0.0;
|
||||
state.install_log.clear();
|
||||
@@ -70,8 +59,26 @@ impl InstallerStep for ExecutionStep {
|
||||
let ctx = ui.ctx().clone();
|
||||
let erase_disk = state.erase_disk;
|
||||
let custom_partitions = state.custom_partitions.clone();
|
||||
let volume_groups = state.volume_groups.clone();
|
||||
let logical_volumes = state.logical_volumes.clone();
|
||||
let selected_disk = state.selected_disk.clone();
|
||||
|
||||
let boot_device = state.bootloader_device.clone();
|
||||
let bootloader_timeout = state.bootloader_timeout;
|
||||
let bootloader_password = state.bootloader_password.clone();
|
||||
let kernel_options = state.kernel_options.clone();
|
||||
let use_ntp = state.use_ntp;
|
||||
let root_password = state.root_password.clone();
|
||||
let display_manager = state.display_manager.clone();
|
||||
let autologin = state.autologin;
|
||||
let desktop_environment = state.desktop_environment.clone();
|
||||
let selected_package_groups = state.selected_package_groups.clone();
|
||||
let manual_year = state.manual_year;
|
||||
let manual_month = state.manual_month;
|
||||
let manual_day = state.manual_day;
|
||||
let manual_hour = state.manual_hour;
|
||||
let manual_minute = state.manual_minute;
|
||||
|
||||
let ui_sender = UiSender::new(tx, ctx);
|
||||
|
||||
thread::spawn(move || {
|
||||
@@ -86,11 +93,34 @@ impl InstallerStep for ExecutionStep {
|
||||
if erase_disk {
|
||||
if let Some(p) = plan {
|
||||
let mut queue = jobs::build_full_job_queue(
|
||||
p, "/mnt", &src,
|
||||
&locale, &timezone,
|
||||
&username, &password, &hostname,
|
||||
&kb_layout, &kb_variant,
|
||||
demo_mode,
|
||||
p,
|
||||
jobs::JobQueueConfig {
|
||||
mount: "/mnt".to_string(),
|
||||
source: src,
|
||||
locale,
|
||||
timezone,
|
||||
username,
|
||||
password,
|
||||
hostname,
|
||||
kb_layout,
|
||||
kb_variant,
|
||||
demo_mode,
|
||||
boot_device,
|
||||
bootloader_timeout,
|
||||
bootloader_password,
|
||||
kernel_options,
|
||||
use_ntp,
|
||||
root_password,
|
||||
display_manager: display_manager.clone(),
|
||||
autologin,
|
||||
desktop_environment: desktop_environment.clone(),
|
||||
selected_package_groups: selected_package_groups.clone(),
|
||||
manual_year,
|
||||
manual_month,
|
||||
manual_day,
|
||||
manual_hour,
|
||||
manual_minute,
|
||||
},
|
||||
);
|
||||
rt.block_on(queue.run_all(ui_sender));
|
||||
} else {
|
||||
@@ -98,14 +128,39 @@ impl InstallerStep for ExecutionStep {
|
||||
t!("error_partition_plan_not_found").to_string()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if let Some(disk) = selected_disk {
|
||||
} else if let Some(disk) = selected_disk {
|
||||
let mut queue = jobs::build_custom_job_queue(
|
||||
disk, custom_partitions, "/mnt", &src,
|
||||
&locale, &timezone,
|
||||
&username, &password, &hostname,
|
||||
&kb_layout, &kb_variant,
|
||||
demo_mode,
|
||||
disk,
|
||||
custom_partitions,
|
||||
volume_groups,
|
||||
logical_volumes,
|
||||
jobs::JobQueueConfig {
|
||||
mount: "/mnt".to_string(),
|
||||
source: src,
|
||||
locale,
|
||||
timezone,
|
||||
username,
|
||||
password,
|
||||
hostname,
|
||||
kb_layout,
|
||||
kb_variant,
|
||||
demo_mode,
|
||||
boot_device,
|
||||
bootloader_timeout,
|
||||
bootloader_password,
|
||||
kernel_options,
|
||||
use_ntp,
|
||||
root_password,
|
||||
display_manager: display_manager.clone(),
|
||||
autologin,
|
||||
desktop_environment: desktop_environment.clone(),
|
||||
selected_package_groups: selected_package_groups.clone(),
|
||||
manual_year,
|
||||
manual_month,
|
||||
manual_day,
|
||||
manual_hour,
|
||||
manual_minute,
|
||||
},
|
||||
);
|
||||
rt.block_on(queue.run_all(ui_sender));
|
||||
} else {
|
||||
@@ -113,7 +168,6 @@ impl InstallerStep for ExecutionStep {
|
||||
t!("error_target_disk_not_selected").to_string()
|
||||
));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::installer::{GlobalState, InstallerStep};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LicenseStep;
|
||||
|
||||
const GPL_TEXT: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/LICENSE"));
|
||||
|
||||
impl InstallerStep for LicenseStep {
|
||||
fn name(&self) -> String {
|
||||
t!("license").to_string()
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.heading(t!("license_title"));
|
||||
ui.label(t!("license_description"));
|
||||
ui.add_space(8.0);
|
||||
|
||||
let avail = ui.available_height();
|
||||
egui::ScrollArea::vertical()
|
||||
.max_height(avail - 60.0)
|
||||
.stick_to_bottom(true)
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
egui::Frame::group(ui.style())
|
||||
.inner_margin(egui::Margin::same(12.0))
|
||||
.show(ui, |ui| {
|
||||
ui.label(
|
||||
egui::RichText::new(GPL_TEXT)
|
||||
.size(14.0)
|
||||
.family(egui::FontFamily::Monospace)
|
||||
.color(egui::Color32::from_rgb(180, 180, 200)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(10.0);
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(egui::Checkbox::new(&mut state.license_accepted, ""));
|
||||
ui.label(
|
||||
egui::RichText::new(t!("license_accept"))
|
||||
.size(14.0)
|
||||
.strong(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn is_complete(&self, state: &GlobalState) -> bool {
|
||||
state.license_accepted
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,12 @@ pub mod summary;
|
||||
pub mod execution;
|
||||
pub mod finish;
|
||||
pub mod partition;
|
||||
pub mod bootloader;
|
||||
pub mod license;
|
||||
pub mod network;
|
||||
pub mod rescue;
|
||||
pub mod display_manager;
|
||||
pub mod netinstall;
|
||||
|
||||
pub use keyboard::KeyboardStep;
|
||||
pub use users::UsersStep;
|
||||
@@ -11,3 +17,8 @@ pub use summary::SummaryStep;
|
||||
pub use execution::ExecutionStep;
|
||||
pub use finish::FinishStep;
|
||||
pub use partition::PartitionStep;
|
||||
pub use bootloader::BootloaderStep;
|
||||
pub use license::LicenseStep;
|
||||
pub use network::NetworkStep;
|
||||
pub use rescue::RescueStep;
|
||||
pub use display_manager::DisplayManagerStep;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::installer::{GlobalState, InstallerStep};
|
||||
|
||||
pub const PACKAGE_GROUPS: &[(&str, &str, &[&str])] = &[
|
||||
("office", "Office Suite", &["libreoffice", "calligra"]),
|
||||
("multimedia", "Multimedia", &["vlc", "audacity", "gimp", "inkscape"]),
|
||||
("development", "Development Tools",&["gcc", "make", "cmake", "git", "python3", "rust"]),
|
||||
("network", "Network Tools", &["firefox", "chromium", "thunderbird", "filezilla"]),
|
||||
("graphics", "Graphics & Design",&["blender", "krita", "darktable"]),
|
||||
("games", "Games", &["steam", "lutris", "supertuxkart"]),
|
||||
("vm", "Virtualization", &["virtualbox", "qemu", "docker"]),
|
||||
("server", "Server", &["nginx", "apache", "mariadb", "postgresql"]),
|
||||
];
|
||||
|
||||
#[derive(Default)]
|
||||
#[allow(dead_code)]
|
||||
pub struct NetinstallStep;
|
||||
|
||||
impl InstallerStep for NetinstallStep {
|
||||
fn name(&self) -> String {
|
||||
t!("netinstall").to_string()
|
||||
}
|
||||
|
||||
fn on_enter(&mut self, state: &mut GlobalState) {
|
||||
if state.selected_package_groups.is_empty() {
|
||||
// Varsayılan ofis ve network
|
||||
state.selected_package_groups = vec!["office".to_string(), "network".to_string()];
|
||||
}
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.heading(t!("netinstall_title"));
|
||||
ui.label(t!("netinstall_description"));
|
||||
ui.add_space(10.0);
|
||||
|
||||
let screen_width = ui.available_width();
|
||||
let cols = if screen_width > 700.0 { 3 } else if screen_width > 500.0 { 2 } else { 1 };
|
||||
|
||||
egui::Grid::new("netinstall_grid")
|
||||
.num_columns(cols)
|
||||
.spacing([8.0, 4.0])
|
||||
.show(ui, |ui| {
|
||||
for (key, label, _pkgs) in PACKAGE_GROUPS {
|
||||
let mut selected = state.selected_package_groups.contains(&key.to_string());
|
||||
ui.checkbox(&mut selected, *label);
|
||||
if selected && !state.selected_package_groups.contains(&key.to_string()) {
|
||||
state.selected_package_groups.push(key.to_string());
|
||||
} else if !selected {
|
||||
state.selected_package_groups.retain(|k| k != key);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(12.0);
|
||||
if !state.selected_package_groups.is_empty() {
|
||||
let total: usize = PACKAGE_GROUPS.iter()
|
||||
.filter(|(k, _, _)| state.selected_package_groups.contains(&k.to_string()))
|
||||
.map(|(_, _, pkgs)| pkgs.len())
|
||||
.sum();
|
||||
ui.label(format!("{} {} {}", total, t!("netinstall_package_count"), t!("netinstall_selected")));
|
||||
}
|
||||
}
|
||||
|
||||
fn is_complete(&self, _state: &GlobalState) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::installer::{GlobalState, InstallerStep};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct NetworkStep {
|
||||
scan_results: Vec<WifiNetwork>,
|
||||
show_password: Vec<bool>,
|
||||
scanning: bool,
|
||||
scan_done: bool,
|
||||
proxy_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct WifiNetwork {
|
||||
ssid: String,
|
||||
signal: String,
|
||||
secured: bool,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl NetworkStep {
|
||||
fn scan_wifi(&mut self) {
|
||||
self.scanning = true;
|
||||
self.scan_done = false;
|
||||
self.scan_results.clear();
|
||||
|
||||
if let Ok(out) = std::process::Command::new("nmcli")
|
||||
.args(["-t", "-f", "SSID,SIGNAL,SECURITY,ACTIVE", "dev", "wifi", "list"])
|
||||
.output()
|
||||
{
|
||||
if out.status.success() {
|
||||
let text = String::from_utf8_lossy(&out.stdout);
|
||||
for line in text.lines() {
|
||||
let parts: Vec<&str> = line.split(':').collect();
|
||||
if parts.len() >= 3 {
|
||||
let ssid = parts[0].trim().to_string();
|
||||
if ssid.is_empty() || ssid == "--" { continue; }
|
||||
self.scan_results.push(WifiNetwork {
|
||||
ssid,
|
||||
signal: parts[1].to_string(),
|
||||
secured: !parts[2].is_empty() && parts[2] != "(none)" && parts[2] != "--",
|
||||
active: parts.get(3).map(|s| s.trim() == "yes").unwrap_or(false),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.show_password = vec![false; self.scan_results.len()];
|
||||
self.scanning = false;
|
||||
self.scan_done = true;
|
||||
}
|
||||
|
||||
fn connect_wifi(ssid: &str, password: &str) -> Result<String, String> {
|
||||
let mut args = vec!["dev", "wifi", "connect", ssid];
|
||||
if !password.is_empty() {
|
||||
args.extend_from_slice(&["password", password]);
|
||||
}
|
||||
let out = std::process::Command::new("nmcli")
|
||||
.args(&args)
|
||||
.output()
|
||||
.map_err(|e| format!("nmcli error: {}", e))?;
|
||||
if out.status.success() {
|
||||
Ok(String::from_utf8_lossy(&out.stdout).trim().to_string())
|
||||
} else {
|
||||
Err(String::from_utf8_lossy(&out.stderr).trim().to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstallerStep for NetworkStep {
|
||||
fn name(&self) -> String {
|
||||
t!("network").to_string()
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.heading(t!("network_title"));
|
||||
ui.label(t!("network_description"));
|
||||
ui.add_space(12.0);
|
||||
|
||||
// Mevcut bağlantı durumu
|
||||
if let Ok(out) = std::process::Command::new("nmcli")
|
||||
.args(["-t", "-f", "DEVICE,TYPE,STATE,CONNECTION", "dev", "status"])
|
||||
.output()
|
||||
{
|
||||
let text = String::from_utf8_lossy(&out.stdout);
|
||||
let connected: Vec<&str> = text.lines()
|
||||
.filter(|l| l.contains(":connected:") || l.contains(":connecting:"))
|
||||
.collect();
|
||||
if !connected.is_empty() {
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(80, 170, 80),
|
||||
format!("{} {}", t!("network_connected"), connected.join(", ")),
|
||||
);
|
||||
} else {
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(200, 140, 40),
|
||||
t!("network_disconnected"),
|
||||
);
|
||||
}
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Proxy ayarları
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(egui::Checkbox::new(&mut self.proxy_enabled, ""));
|
||||
ui.label(t!("network_proxy_label"));
|
||||
});
|
||||
if self.proxy_enabled {
|
||||
egui::Grid::new("proxy_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 6.0])
|
||||
.show(ui, |ui| {
|
||||
ui.label("HTTP:");
|
||||
ui.text_edit_singleline(&mut state.network_http_proxy);
|
||||
ui.end_row();
|
||||
ui.label("HTTPS:");
|
||||
ui.text_edit_singleline(&mut state.network_https_proxy);
|
||||
ui.end_row();
|
||||
ui.label("FTP:");
|
||||
ui.text_edit_singleline(&mut state.network_ftp_proxy);
|
||||
ui.end_row();
|
||||
});
|
||||
}
|
||||
ui.add_space(12.0);
|
||||
|
||||
// Wi-Fi tara
|
||||
if !self.scan_done {
|
||||
if ui.add(egui::Button::new(t!("network_scan"))).clicked() {
|
||||
self.scan_wifi();
|
||||
}
|
||||
} else {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.add(egui::Button::new(t!("network_rescan"))).clicked() {
|
||||
self.scan_done = false;
|
||||
}
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{}: {}", t!("network_scan_count"), self.scan_results.len()))
|
||||
.size(12.0)
|
||||
.color(egui::Color32::from_rgb(120, 120, 140)),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Wi-Fi listesi
|
||||
if !self.scan_results.is_empty() {
|
||||
egui::ScrollArea::vertical()
|
||||
.max_height(300.0)
|
||||
.show(ui, |ui| {
|
||||
egui::Frame::group(ui.style())
|
||||
.inner_margin(egui::Margin::same(6.0))
|
||||
.show(ui, |ui| {
|
||||
for (i, net) in self.scan_results.clone().iter().enumerate() {
|
||||
ui.horizontal(|ui| {
|
||||
let lock = if net.secured { "🔒" } else { "🌐" };
|
||||
let sig = net.signal.parse::<i32>().unwrap_or(0);
|
||||
let bars = if sig > -50 { "▂▄▆█" } else if sig > -67 { "▂▄▆" } else if sig > -80 { "▂▄" } else { "▂" };
|
||||
let active = if net.active { " ✓" } else { "" };
|
||||
|
||||
ui.label(format!("{} {}{}", lock, net.ssid, active));
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
ui.label(
|
||||
egui::RichText::new(bars)
|
||||
.size(10.0)
|
||||
.color(egui::Color32::from_rgb(120, 120, 140)),
|
||||
);
|
||||
if net.secured && !net.active {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.network_wifi_password)
|
||||
.password(!self.show_password.get(i).copied().unwrap_or(false))
|
||||
.hint_text(t!("network_password_hint"))
|
||||
.desired_width(120.0));
|
||||
if ui.small_button("👁").clicked() {
|
||||
if self.show_password.len() <= i {
|
||||
self.show_password.resize(i + 1, false);
|
||||
}
|
||||
self.show_password[i] = !self.show_password[i];
|
||||
}
|
||||
}
|
||||
if !net.active && ui.add(egui::Button::new(t!("network_connect"))).clicked() {
|
||||
let pw = if net.secured { state.network_wifi_password.clone() } else { String::new() };
|
||||
match Self::connect_wifi(&net.ssid, &pw) {
|
||||
Ok(msg) => {
|
||||
state.install_log.push(format!("Wi-Fi: {} — {}", net.ssid, msg));
|
||||
self.scan_done = false;
|
||||
}
|
||||
Err(e) => {
|
||||
state.install_log.push(format!("Wi-Fi error: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.separator();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn is_complete(&self, _state: &GlobalState) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
+440
-36
@@ -5,11 +5,84 @@ use rust_i18n::t;
|
||||
// sysinfo::Disks mount point başına bir kayıt döndürür (partition'lar),
|
||||
// ham disk listesi için lsblk kullanıyoruz.
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Mevcut disk bölümlerini oku
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
/// Verilen diskin (`/dev/sda`, `/dev/nvme0n1` vb.) mevcut bölümlerini
|
||||
/// `lsblk` aracılığıyla okur ve `CustomPartition` listesi olarak döndürür.
|
||||
///
|
||||
/// Hem SATA/virtio tipi (`sda` → `sda1`, `sda2`) hem de NVMe tipi
|
||||
/// (`nvme0n1` → `nvme0n1p1`, `nvme0n1p2`) aygıtları desteklenir.
|
||||
/// Manuel bölümleme modunda disk seçildiğinde çağrılır; böylece kullanıcı
|
||||
/// diskin mevcut bölüm düzenini görebilir.
|
||||
fn read_existing_partitions(disk_path: &str) -> Vec<crate::installer::CustomPartition> {
|
||||
use crate::installer::{CustomPartition, FsType};
|
||||
|
||||
let dev_name = disk_path.trim_start_matches("/dev/");
|
||||
|
||||
let out = std::process::Command::new("lsblk")
|
||||
.args([
|
||||
"-o", "NAME,SIZE,FSTYPE,MOUNTPOINT",
|
||||
"-b", "--noheadings", "-l",
|
||||
disk_path,
|
||||
])
|
||||
.output();
|
||||
|
||||
let mut parts = Vec::new();
|
||||
|
||||
if let Ok(o) = out {
|
||||
if o.status.success() {
|
||||
let text = String::from_utf8_lossy(&o.stdout);
|
||||
for line in text.lines() {
|
||||
let mut tokens = line.split_whitespace();
|
||||
|
||||
let name = match tokens.next() { Some(n) => n, None => continue };
|
||||
|
||||
// Diskin kendisini (örn. "sda") atla — yalnızca bölümleri al
|
||||
if name == dev_name { continue; }
|
||||
|
||||
// Bu diske ait olmayan girişleri atla
|
||||
// SATA: sda1, sda2 … NVMe: nvme0n1p1, nvme0n1p2 …
|
||||
if !name.starts_with(dev_name) { continue; }
|
||||
|
||||
let size_bytes: u64 = tokens.next().unwrap_or("0").parse().unwrap_or(0);
|
||||
let size_mb = size_bytes / (1024 * 1024);
|
||||
|
||||
let fstype_str = tokens.next().unwrap_or("");
|
||||
let fstype = match fstype_str {
|
||||
"ext4" => FsType::Ext4,
|
||||
"ext3" => FsType::Ext3,
|
||||
"btrfs" => FsType::Btrfs,
|
||||
"xfs" => FsType::Xfs,
|
||||
"vfat" => FsType::Fat32,
|
||||
"ntfs" => FsType::Ntfs,
|
||||
"swap" => FsType::Swap,
|
||||
_ => FsType::Ext4, // bilinmeyen → varsayılan
|
||||
};
|
||||
|
||||
// lsblk mount point alanı boşsa sonraki token gelmez; unwrap_or ile güvenli al
|
||||
let mountpoint = tokens.next().unwrap_or("").to_string();
|
||||
|
||||
parts.push(CustomPartition {
|
||||
device: format!("/dev/{}", name),
|
||||
size_mb,
|
||||
fstype,
|
||||
mountpoint,
|
||||
encrypt: false,
|
||||
luks_password: String::new(),
|
||||
luks_name: String::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parts
|
||||
}
|
||||
|
||||
/// `/sys/block` altındaki gerçek blok aygıtlarını (partition değil) listeler.
|
||||
/// lsblk'dan JSON çıktısı ayrıştırılır; başarısız olursa /sys/block fallback.
|
||||
/// lsblk'dan gelen çıktı akıllıca ayrıştırılır; başarısız olursa /sys/block fallback devreye girer.
|
||||
fn list_block_devices() -> Vec<crate::installer::DiskInfo> {
|
||||
// lsblk -d: sadece diskler (partition'lar hariç)
|
||||
// -o NAME,SIZE,MODEL,TYPE -b: byte cinsinden boyut
|
||||
let out = std::process::Command::new("lsblk")
|
||||
.args(["-d", "-o", "NAME,SIZE,MODEL", "-b", "--noheadings"])
|
||||
.output();
|
||||
@@ -17,43 +90,64 @@ fn list_block_devices() -> Vec<crate::installer::DiskInfo> {
|
||||
let mut disks = Vec::new();
|
||||
|
||||
if let Ok(o) = out {
|
||||
let text = String::from_utf8_lossy(&o.stdout);
|
||||
for line in text.lines() {
|
||||
let cols: Vec<&str> = line.splitn(3, char::is_whitespace)
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
if cols.len() < 2 { continue; }
|
||||
if o.status.success() {
|
||||
let text = String::from_utf8_lossy(&o.stdout);
|
||||
for line in text.lines() {
|
||||
// split_whitespace ardışık tüm boşlukları tek bir ayırıcı gibi yakalar
|
||||
let mut tokens = line.split_whitespace();
|
||||
|
||||
let name_raw = match tokens.next() {
|
||||
Some(n) => n,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let name_raw = cols[0]; // örn. "sda" veya "nvme0n1"
|
||||
// loop, ram, sr aygıtlarını atla
|
||||
if name_raw.starts_with("loop")
|
||||
|| name_raw.starts_with("ram")
|
||||
|| name_raw.starts_with("sr")
|
||||
{ continue; }
|
||||
// loop, ram, sr (CD-ROM) ve zram aygıtlarını atla
|
||||
if name_raw.starts_with("loop")
|
||||
|| name_raw.starts_with("ram")
|
||||
|| name_raw.starts_with("sr")
|
||||
|| name_raw.starts_with("zram")
|
||||
{ continue; }
|
||||
|
||||
let size_bytes: u64 = cols[1].trim().parse().unwrap_or(0);
|
||||
let model = if cols.len() >= 3 { cols[2].trim() } else { "" };
|
||||
let size_str = match tokens.next() {
|
||||
Some(s) => s,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
disks.push(crate::installer::DiskInfo {
|
||||
name: format!("/dev/{}", name_raw),
|
||||
model: model.to_string(),
|
||||
size_gb: size_bytes / 1_073_741_824,
|
||||
size_bytes,
|
||||
});
|
||||
let size_bytes: u64 = size_str.parse().unwrap_or(0);
|
||||
// Eğer boyut 0 ise ekleme yapma ki lsblk patlarsa fallback çalışabilsin
|
||||
if size_bytes == 0 { continue; }
|
||||
|
||||
// Kalan tüm token'lar model ismidir (örn: ["VBOX", "HARDDISK"])
|
||||
let model_tokens: Vec<&str> = tokens.collect();
|
||||
let model = model_tokens.join(" ");
|
||||
|
||||
disks.push(crate::installer::DiskInfo {
|
||||
name: format!("/dev/{}", name_raw),
|
||||
model,
|
||||
size_gb: size_bytes / 1_073_741_824,
|
||||
size_bytes,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lsblk başarısız olduysa /sys/block fallback
|
||||
// lsblk başarısız olduysa veya geçerli disk bulamadıysa temiz /sys/block fallback'i çalışır
|
||||
if disks.is_empty() {
|
||||
if let Ok(rd) = std::fs::read_dir("/sys/block") {
|
||||
for entry in rd.flatten() {
|
||||
let name = entry.file_name().to_string_lossy().to_string();
|
||||
if name.starts_with("loop") || name.starts_with("ram") { continue; }
|
||||
|
||||
if name.starts_with("loop")
|
||||
|| name.starts_with("ram")
|
||||
|| name.starts_with("sr")
|
||||
|| name.starts_with("zram")
|
||||
{ continue; }
|
||||
|
||||
let size_path = format!("/sys/block/{}/size", name);
|
||||
let size_sectors: u64 = std::fs::read_to_string(&size_path)
|
||||
.unwrap_or_default().trim().parse().unwrap_or(0);
|
||||
let size_bytes = size_sectors * 512;
|
||||
if size_bytes == 0 { continue; }
|
||||
|
||||
let model_path = format!("/sys/block/{}/device/model", name);
|
||||
let model = std::fs::read_to_string(&model_path)
|
||||
@@ -74,7 +168,7 @@ fn list_block_devices() -> Vec<crate::installer::DiskInfo> {
|
||||
|
||||
use crate::installer::{
|
||||
CustomPartition, DiskInfo, FsType, GlobalState, InstallerStep,
|
||||
PartitionPlan, PartitionTableType,
|
||||
PartitionPlan, PartitionTableType, VolumeGroup,
|
||||
};
|
||||
|
||||
const MIN_DISK_GB: u64 = 10;
|
||||
@@ -96,18 +190,35 @@ struct ManualState {
|
||||
add_size_str: String,
|
||||
/// Diyalog: bağlama noktası
|
||||
add_mountpoint: String,
|
||||
/// Diyalog: LUKS şifrele
|
||||
add_encrypt: bool,
|
||||
/// Diyalog: LUKS parola
|
||||
add_luks_password: String,
|
||||
/// Silinmek istenen bölüm indeksi (onay isteği)
|
||||
delete_idx: Option<usize>,
|
||||
/// Genel hata mesajı
|
||||
error: Option<String>,
|
||||
/// Yeni VG adı (LVM)
|
||||
add_vg_name: String,
|
||||
|
||||
// ── LVM Logical Volume Ekleme State'leri ───────────────────
|
||||
adding_lv: bool,
|
||||
add_lv_name: String,
|
||||
add_lv_vg_idx: usize,
|
||||
add_lv_size_str: String,
|
||||
add_lv_fstype: usize,
|
||||
add_lv_mountpoint: String,
|
||||
}
|
||||
|
||||
const FS_OPTIONS: &[(&str, FsType)] = &[
|
||||
("ext4", FsType::Ext4),
|
||||
("ext3", FsType::Ext3),
|
||||
("btrfs", FsType::Btrfs),
|
||||
("xfs", FsType::Xfs),
|
||||
("FAT32 (EFI)", FsType::Fat32),
|
||||
("NTFS", FsType::Ntfs),
|
||||
("swap", FsType::Swap),
|
||||
("LVM PV", FsType::Lvm),
|
||||
];
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
@@ -118,6 +229,7 @@ pub struct PartitionStep {
|
||||
scanned: bool,
|
||||
is_uefi: bool,
|
||||
manual: ManualState,
|
||||
show_luks_password: bool,
|
||||
}
|
||||
|
||||
impl Default for PartitionStep {
|
||||
@@ -126,6 +238,7 @@ impl Default for PartitionStep {
|
||||
scanned: false,
|
||||
is_uefi: std::path::Path::new("/sys/firmware/efi").exists(),
|
||||
manual: ManualState::default(),
|
||||
show_luks_password: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,12 +276,19 @@ fn make_plan(disk: &DiskInfo, is_uefi: bool) -> Option<PartitionPlan> {
|
||||
efi_mb,
|
||||
swap_mb,
|
||||
root_mb,
|
||||
encrypt_root: false,
|
||||
luks_password: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Manuel listedeki bölümlerin geçerliliğini kontrol eder.
|
||||
fn validate_manual(parts: &[CustomPartition], is_uefi: bool) -> Option<String> {
|
||||
let has_root = parts.iter().any(|p| p.mountpoint == "/");
|
||||
fn validate_manual(
|
||||
parts: &[CustomPartition],
|
||||
lvs: &[crate::installer::LogicalVolume],
|
||||
is_uefi: bool,
|
||||
) -> Option<String> {
|
||||
let has_root = parts.iter().any(|p| p.mountpoint == "/")
|
||||
|| lvs.iter().any(|lv| lv.mountpoint == "/");
|
||||
let has_efi = parts.iter().any(|p| p.mountpoint == "/boot/efi" || p.fstype == FsType::Fat32);
|
||||
|
||||
if !has_root {
|
||||
@@ -224,7 +344,7 @@ impl InstallerStep for PartitionStep {
|
||||
state.partition_plan.is_some()
|
||||
} else {
|
||||
!state.custom_partitions.is_empty()
|
||||
&& validate_manual(&state.custom_partitions, self.is_uefi).is_none()
|
||||
&& validate_manual(&state.custom_partitions, &state.logical_volumes, self.is_uefi).is_none()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,7 +354,7 @@ impl InstallerStep for PartitionStep {
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
impl PartitionStep {
|
||||
fn show_auto_mode(&self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
fn show_auto_mode(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.group(|ui| {
|
||||
ui.label(t!("select_disk_label"));
|
||||
ui.add_space(4.0);
|
||||
@@ -296,6 +416,30 @@ impl PartitionStep {
|
||||
ui.add_space(8.0);
|
||||
ui.label(format!("{}: {}", t!("partition_table_type"), plan.table_type));
|
||||
|
||||
// ── LUKS şifreleme ─────────────────────────────────────
|
||||
ui.add_space(12.0);
|
||||
ui.separator();
|
||||
ui.add_space(8.0);
|
||||
let plan = state.partition_plan.as_mut().unwrap();
|
||||
ui.checkbox(&mut plan.encrypt_root, t!("luks_enable_root"));
|
||||
if plan.encrypt_root {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(t!("luks_password"));
|
||||
if self.show_luks_password {
|
||||
ui.text_edit_singleline(&mut plan.luks_password);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut plan.luks_password).password(true));
|
||||
}
|
||||
let eye = if self.show_luks_password { "🙈" } else { "👁" };
|
||||
if ui.small_button(eye).clicked() {
|
||||
self.show_luks_password = !self.show_luks_password;
|
||||
}
|
||||
});
|
||||
if plan.luks_password.len() < 4 && !plan.luks_password.is_empty() {
|
||||
ui.colored_label(egui::Color32::YELLOW, t!("luks_password_weak"));
|
||||
}
|
||||
}
|
||||
|
||||
ui.add_space(10.0);
|
||||
egui::Frame::none()
|
||||
.fill(egui::Color32::from_rgba_unmultiplied(200, 60, 40, 25))
|
||||
@@ -329,8 +473,9 @@ impl PartitionStep {
|
||||
let label = egui::RichText::new(format!("{} — {} GB ({})", disk.name, disk.size_gb, disk.model)).strong().color(crate::ui::theme::c_accent());
|
||||
if ui.radio(selected, label).clicked() {
|
||||
state.selected_disk = Some(disk.name.clone());
|
||||
// Disk değişince listeyi sıfırla
|
||||
state.custom_partitions.clear();
|
||||
// Disk değişince mevcut bölümleri oku ve listeyi güncelle.
|
||||
// Böylece kullanıcı diskin mevcut düzenini görebilir.
|
||||
state.custom_partitions = read_existing_partitions(&disk.name);
|
||||
self.manual.error = None;
|
||||
}
|
||||
}
|
||||
@@ -375,8 +520,12 @@ impl PartitionStep {
|
||||
};
|
||||
|
||||
ui.label(&part.device);
|
||||
let mut fstype_label = part.fstype.label().to_string();
|
||||
if part.encrypt {
|
||||
fstype_label = format!("🔐 {}", fstype_label);
|
||||
}
|
||||
ui.label(&size_str);
|
||||
ui.label(part.fstype.label());
|
||||
ui.label(fstype_label);
|
||||
ui.label(&part.mountpoint);
|
||||
if ui.small_button("🗑").on_hover_text(t!("mp_delete")).clicked() {
|
||||
delete_idx = Some(i);
|
||||
@@ -451,7 +600,7 @@ impl PartitionStep {
|
||||
// Dosya sistemi
|
||||
ui.label(t!("mp_fstype"));
|
||||
egui::ComboBox::from_id_source("fs_combo")
|
||||
.selected_text(FS_OPTIONS[self.manual.add_fstype].0)
|
||||
.selected_text(FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.0).unwrap_or("?"))
|
||||
.show_ui(ui, |ui| {
|
||||
for (i, (label, _)) in FS_OPTIONS.iter().enumerate() {
|
||||
ui.selectable_value(
|
||||
@@ -472,6 +621,33 @@ impl PartitionStep {
|
||||
.hint_text(t!("mp_add_dialog_hint"));
|
||||
ui.add(mp_field);
|
||||
ui.end_row();
|
||||
|
||||
// LUKS şifreleme
|
||||
ui.label(t!("luks_enable_root"));
|
||||
let fstype = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
|
||||
let can_encrypt = matches!(fstype, FsType::Ext4 | FsType::Ext3 | FsType::Btrfs | FsType::Xfs);
|
||||
ui.add_enabled_ui(can_encrypt, |ui| {
|
||||
ui.checkbox(&mut self.manual.add_encrypt, "");
|
||||
});
|
||||
if !can_encrypt { self.manual.add_encrypt = false; }
|
||||
ui.end_row();
|
||||
|
||||
if self.manual.add_encrypt {
|
||||
ui.label(t!("luks_password"));
|
||||
let pw = &mut self.manual.add_luks_password;
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_luks_password {
|
||||
ui.text_edit_singleline(pw);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(pw).password(true));
|
||||
}
|
||||
let eye = if self.show_luks_password { "🙈" } else { "👁" };
|
||||
if ui.small_button(eye).clicked() {
|
||||
self.show_luks_password = !self.show_luks_password;
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(8.0);
|
||||
@@ -481,19 +657,26 @@ impl PartitionStep {
|
||||
let size_mb: u64 = self.manual.add_size_str
|
||||
.trim().parse().unwrap_or(0);
|
||||
let mp = self.manual.add_mountpoint.trim().to_string();
|
||||
let fstype = FS_OPTIONS[self.manual.add_fstype].1.clone();
|
||||
let fstype = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
|
||||
let part_num = state.custom_partitions.len() + 1;
|
||||
let device = crate::installer::part_path(&disk, part_num as u32);
|
||||
|
||||
if mp.is_empty() {
|
||||
self.manual.error = Some(t!("mp_error_empty_mountpoint").to_string());
|
||||
} else {
|
||||
let encrypt = self.manual.add_encrypt;
|
||||
let luks_password = if encrypt { self.manual.add_luks_password.clone() } else { String::new() };
|
||||
state.custom_partitions.push(CustomPartition {
|
||||
device,
|
||||
size_mb,
|
||||
fstype,
|
||||
mountpoint: mp,
|
||||
encrypt,
|
||||
luks_password,
|
||||
luks_name: String::new(),
|
||||
});
|
||||
self.manual.add_encrypt = false;
|
||||
self.manual.add_luks_password.clear();
|
||||
self.manual.error = None;
|
||||
self.manual.adding = false;
|
||||
}
|
||||
@@ -505,13 +688,234 @@ impl PartitionStep {
|
||||
});
|
||||
}
|
||||
|
||||
// ── LVM Yapılandırması ──────────────────────────────────
|
||||
ui.add_space(12.0);
|
||||
let has_lvm_pvs = state.custom_partitions.iter().any(|p| p.fstype == FsType::Lvm);
|
||||
if has_lvm_pvs {
|
||||
ui.label(egui::RichText::new("LVM Volume Groups").strong().size(14.0));
|
||||
ui.add_space(4.0);
|
||||
egui::Grid::new("lvm_vg_grid")
|
||||
.num_columns(4)
|
||||
.spacing([12.0, 6.0])
|
||||
.striped(true)
|
||||
.show(ui, |ui| {
|
||||
ui.label("VG Name");
|
||||
ui.label("PV Devices");
|
||||
ui.label("Size");
|
||||
ui.label("");
|
||||
ui.end_row();
|
||||
|
||||
let mut remove_vg: Option<usize> = None;
|
||||
for (vi, vg) in state.volume_groups.iter().enumerate() {
|
||||
let pv_list = vg.pv_devices.join(", ");
|
||||
let size_str = if vg.size_mb >= 1024 {
|
||||
format!("{:.1} GB", vg.size_mb as f64 / 1024.0)
|
||||
} else {
|
||||
format!("{} MB", vg.size_mb)
|
||||
};
|
||||
ui.label(&vg.name);
|
||||
ui.label(&pv_list);
|
||||
ui.label(&size_str);
|
||||
if ui.small_button("🗑").clicked() {
|
||||
remove_vg = Some(vi);
|
||||
}
|
||||
ui.end_row();
|
||||
}
|
||||
if let Some(vi) = remove_vg {
|
||||
state.volume_groups.remove(vi);
|
||||
}
|
||||
|
||||
// Yeni VG ekleme
|
||||
ui.horizontal(|ui| {
|
||||
ui.text_edit_singleline(&mut self.manual.add_vg_name);
|
||||
if ui.small_button("➕ VG").clicked()
|
||||
&& !self.manual.add_vg_name.is_empty()
|
||||
{
|
||||
let pvs: Vec<String> = state.custom_partitions.iter()
|
||||
.filter(|p| p.fstype == FsType::Lvm)
|
||||
.map(|p| p.device.clone())
|
||||
.collect();
|
||||
let size: u64 = state.custom_partitions.iter()
|
||||
.filter(|p| p.fstype == FsType::Lvm)
|
||||
.map(|p| p.size_mb)
|
||||
.sum();
|
||||
state.volume_groups.push(VolumeGroup {
|
||||
name: self.manual.add_vg_name.clone(),
|
||||
pv_devices: pvs,
|
||||
size_mb: size,
|
||||
});
|
||||
self.manual.add_vg_name.clear();
|
||||
}
|
||||
});
|
||||
ui.label("");
|
||||
ui.label("");
|
||||
ui.end_row();
|
||||
});
|
||||
|
||||
// ── LVM Logical Volumes Tablosu ──────────────────────────
|
||||
let has_vgs = !state.volume_groups.is_empty();
|
||||
if has_vgs {
|
||||
ui.add_space(12.0);
|
||||
ui.label(egui::RichText::new(t!("lvm_lv_title")).strong().size(14.0));
|
||||
ui.add_space(4.0);
|
||||
|
||||
let mut remove_lv: Option<usize> = None;
|
||||
egui::Grid::new("lvm_lv_grid")
|
||||
.num_columns(5)
|
||||
.spacing([12.0, 6.0])
|
||||
.striped(true)
|
||||
.show(ui, |ui| {
|
||||
ui.label(egui::RichText::new(t!("lvm_lv_name")).strong().color(crate::ui::theme::c_text()));
|
||||
ui.label(egui::RichText::new(t!("lvm_lv_vg")).strong().color(crate::ui::theme::c_text()));
|
||||
ui.label(egui::RichText::new(t!("mp_size")).strong().color(crate::ui::theme::c_text()));
|
||||
ui.label(egui::RichText::new(t!("mp_mountpoint")).strong().color(crate::ui::theme::c_text()));
|
||||
ui.label(egui::RichText::new(t!("mp_action")).strong().color(crate::ui::theme::c_text()));
|
||||
ui.end_row();
|
||||
|
||||
for (li, lv) in state.logical_volumes.iter().enumerate() {
|
||||
let size_str = if lv.size_mb == 0 {
|
||||
t!("mp_size_remaining").to_string()
|
||||
} else {
|
||||
format!("{} MB", lv.size_mb)
|
||||
};
|
||||
ui.label(&lv.name);
|
||||
ui.label(&lv.vg_name);
|
||||
ui.label(size_str);
|
||||
ui.label(&lv.mountpoint);
|
||||
if ui.small_button("🗑").clicked() {
|
||||
remove_lv = Some(li);
|
||||
}
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(li) = remove_lv {
|
||||
state.logical_volumes.remove(li);
|
||||
}
|
||||
|
||||
ui.add_space(8.0);
|
||||
// "Logical Volume Ekle" butonu
|
||||
let lv_btn = egui::Button::new(format!("➕ {}", t!("lvm_lv_add")))
|
||||
.fill(accent.gamma_multiply(0.15));
|
||||
if ui.add(lv_btn).clicked() {
|
||||
self.manual.adding_lv = true;
|
||||
self.manual.add_lv_name.clear();
|
||||
self.manual.add_lv_vg_idx = 0;
|
||||
self.manual.add_lv_size_str.clear();
|
||||
self.manual.add_lv_fstype = 0;
|
||||
self.manual.add_lv_mountpoint.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Logical Volume Ekleme Diyaloğu ────────────────────────
|
||||
if self.manual.adding_lv {
|
||||
egui::Window::new(t!("lvm_lv_add"))
|
||||
.collapsible(false)
|
||||
.resizable(false)
|
||||
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
|
||||
.show(ui.ctx(), |ui| {
|
||||
egui::Grid::new("add_lv_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 8.0])
|
||||
.show(ui, |ui| {
|
||||
// Hacim Grubu (VG) seçimi
|
||||
ui.label(t!("lvm_lv_vg"));
|
||||
let current_vg = state.volume_groups.get(self.manual.add_lv_vg_idx)
|
||||
.map(|vg| vg.name.as_str())
|
||||
.unwrap_or("?");
|
||||
egui::ComboBox::from_id_source("lv_vg_combo")
|
||||
.selected_text(current_vg)
|
||||
.show_ui(ui, |ui| {
|
||||
for (vi, vg) in state.volume_groups.iter().enumerate() {
|
||||
ui.selectable_value(
|
||||
&mut self.manual.add_lv_vg_idx, vi, &vg.name
|
||||
);
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// LV Adı
|
||||
ui.label(t!("lvm_lv_name"));
|
||||
ui.text_edit_singleline(&mut self.manual.add_lv_name);
|
||||
ui.end_row();
|
||||
|
||||
// Dosya sistemi
|
||||
ui.label(t!("mp_fstype"));
|
||||
egui::ComboBox::from_id_source("lv_fs_combo")
|
||||
.selected_text(FS_OPTIONS.get(self.manual.add_lv_fstype).map(|x| x.0).unwrap_or("?"))
|
||||
.show_ui(ui, |ui| {
|
||||
for (i, (label, _)) in FS_OPTIONS.iter().enumerate() {
|
||||
ui.selectable_value(
|
||||
&mut self.manual.add_lv_fstype, i, *label
|
||||
);
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Boyut
|
||||
ui.label(t!("mp_size_hint"));
|
||||
ui.text_edit_singleline(&mut self.manual.add_lv_size_str);
|
||||
ui.end_row();
|
||||
|
||||
// Bağlama noktası
|
||||
ui.label(t!("mp_mountpoint"));
|
||||
let mp_field = egui::TextEdit::singleline(&mut self.manual.add_lv_mountpoint)
|
||||
.hint_text(t!("mp_add_dialog_hint"));
|
||||
ui.add(mp_field);
|
||||
ui.end_row();
|
||||
});
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.horizontal(|ui| {
|
||||
let ok_btn = egui::Button::new(t!("mp_add_btn")).fill(accent.gamma_multiply(0.2));
|
||||
if ui.add(ok_btn).clicked() {
|
||||
let size_mb: u64 = self.manual.add_lv_size_str.trim().parse().unwrap_or(0);
|
||||
let mp = self.manual.add_lv_mountpoint.trim().to_string();
|
||||
let lv_name = self.manual.add_lv_name.trim().to_string();
|
||||
let fstype = FS_OPTIONS.get(self.manual.add_lv_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
|
||||
|
||||
if lv_name.is_empty() {
|
||||
self.manual.error = Some("LV Adı boş olamaz.".to_string());
|
||||
} else if mp.is_empty() {
|
||||
self.manual.error = Some(t!("mp_error_empty_mountpoint").to_string());
|
||||
} else if let Some(vg) = state.volume_groups.get(self.manual.add_lv_vg_idx) {
|
||||
// VG sınır doğrulaması
|
||||
let current_sum: u64 = state.logical_volumes.iter()
|
||||
.filter(|lv| lv.vg_name == vg.name)
|
||||
.map(|lv| lv.size_mb)
|
||||
.sum();
|
||||
if current_sum + size_mb > vg.size_mb && size_mb > 0 {
|
||||
self.manual.error = Some(t!("lvm_lv_error_size").to_string());
|
||||
} else {
|
||||
state.logical_volumes.push(crate::installer::LogicalVolume {
|
||||
name: lv_name,
|
||||
vg_name: vg.name.clone(),
|
||||
size_mb,
|
||||
fstype,
|
||||
mountpoint: mp,
|
||||
});
|
||||
self.manual.error = None;
|
||||
self.manual.adding_lv = false;
|
||||
}
|
||||
} else {
|
||||
self.manual.error = Some(t!("lvm_lv_error_vg").to_string());
|
||||
}
|
||||
}
|
||||
if ui.button(t!("cancel")).clicked() {
|
||||
self.manual.adding_lv = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ── Doğrulama mesajları ─────────────────────────────────
|
||||
ui.add_space(6.0);
|
||||
if let Some(ref err) = self.manual.error {
|
||||
ui.colored_label(egui::Color32::from_rgb(217, 0, 91), err);
|
||||
}
|
||||
if !state.custom_partitions.is_empty() {
|
||||
if let Some(warn) = validate_manual(&state.custom_partitions, self.is_uefi) {
|
||||
if let Some(warn) = validate_manual(&state.custom_partitions, &state.logical_volumes, self.is_uefi) {
|
||||
ui.colored_label(egui::Color32::from_rgb(220, 160, 40), warn);
|
||||
} else {
|
||||
ui.colored_label(
|
||||
|
||||
@@ -0,0 +1,516 @@
|
||||
//! Kurtarma modu adımı.
|
||||
//!
|
||||
//! Özellikler:
|
||||
//! - Mevcut Linux kurulumlarını tarar (lsblk)
|
||||
//! - Seçilen bölümü /mnt'a bağlar
|
||||
//! - chroot kabuğu başlatır
|
||||
//! - GRUB'u yeniden yükler
|
||||
//! - **Pisi paket geçmişini listeler ve `pisi takeback <N>` ile geri alır**
|
||||
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::installer::{GlobalState, InstallerStep};
|
||||
use crate::ui::theme;
|
||||
|
||||
/// Pisi geçmişindeki tek bir işlem kaydı.
|
||||
#[derive(Clone, Debug)]
|
||||
struct PisiHistoryEntry {
|
||||
/// İşlem numarası (takeback argümanı)
|
||||
pub op: u32,
|
||||
/// Tarih/saat dizisi
|
||||
pub date: String,
|
||||
/// İşlem türü (install, remove, upgrade, …)
|
||||
pub op_type: String,
|
||||
/// Etkilenen paket sayısı veya açıklaması
|
||||
pub summary: String,
|
||||
}
|
||||
|
||||
/// Pisi geçmiş geri alma modunun durumu.
|
||||
#[derive(Default)]
|
||||
struct PisiHistoryState {
|
||||
entries: Vec<PisiHistoryEntry>,
|
||||
selected: Option<usize>,
|
||||
scanned: bool,
|
||||
running: bool,
|
||||
result_msg: Option<String>,
|
||||
result_ok: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RescueStep {
|
||||
detected: Vec<String>,
|
||||
selected: Option<usize>,
|
||||
log: Vec<String>,
|
||||
mount_done: bool,
|
||||
pisi: PisiHistoryState,
|
||||
/// Aktif sekme: 0=Chroot/GRUB, 1=Pisi Geçmiş
|
||||
tab: usize,
|
||||
}
|
||||
|
||||
impl RescueStep {
|
||||
fn detect_installations(&mut self) {
|
||||
self.detected.clear();
|
||||
self.mount_done = false;
|
||||
if let Ok(out) = std::process::Command::new("lsblk")
|
||||
.args(["-o", "NAME,FSTYPE,MOUNTPOINT", "-l", "-n"])
|
||||
.output()
|
||||
{
|
||||
let text = String::from_utf8_lossy(&out.stdout);
|
||||
for line in text.lines() {
|
||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||
if parts.len() >= 2 {
|
||||
let fstype = parts[1];
|
||||
if fstype == "ext4" || fstype == "btrfs" || fstype == "xfs" {
|
||||
let dev = format!("/dev/{}", parts[0]);
|
||||
let mp = parts.get(2).unwrap_or(&"-").to_string();
|
||||
self.detected.push(format!("{} ({}) [{}]", dev, fstype, mp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Seçili bölümü /mnt'a bağlar. Başarılıysa `true` döner.
|
||||
fn mount_selected(&mut self) -> bool {
|
||||
if let Some(idx) = self.selected {
|
||||
if let Some(entry) = self.detected.get(idx) {
|
||||
// Entry: "/dev/sda1 (ext4) [-]" — sadece ilk token aygıt yolu
|
||||
let dev = entry.split_whitespace().next().unwrap_or("");
|
||||
if dev.is_empty() { return false; }
|
||||
// /mnt boşsa bağla
|
||||
let r = std::process::Command::new("mount")
|
||||
.args([dev, "/mnt"])
|
||||
.status();
|
||||
if let Ok(s) = r {
|
||||
if s.success() {
|
||||
self.mount_done = true;
|
||||
self.log.push(format!("✓ {} → /mnt bağlandı.", dev));
|
||||
return true;
|
||||
} else {
|
||||
self.log.push(format!("⚠ {} bağlanamadı (zaten bağlı veya hata).", dev));
|
||||
self.mount_done = true; // Belki zaten bağlı
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn run_rescue_cmd(cmd: &str, args: &[&str]) -> Result<String, String> {
|
||||
let out = std::process::Command::new(cmd)
|
||||
.args(args)
|
||||
.output()
|
||||
.map_err(|e| format!("{} hatası: {}", cmd, e))?;
|
||||
if out.status.success() {
|
||||
Ok(String::from_utf8_lossy(&out.stdout).trim().to_string())
|
||||
} else {
|
||||
Err(String::from_utf8_lossy(&out.stderr).trim().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// `pisi history` çıktısını ayrıştırır.
|
||||
/// Örnek satır: "Operation 42 [2024-03-15 12:00:01]: install [vim]"
|
||||
fn parse_pisi_history(raw: &str) -> Vec<PisiHistoryEntry> {
|
||||
let mut entries = Vec::new();
|
||||
for line in raw.lines() {
|
||||
let line = line.trim();
|
||||
if line.is_empty() || line.starts_with('#') { continue; }
|
||||
|
||||
// "Operation 42 [2024-03-15 12:00:01]: install [vim, curl]"
|
||||
if let Some(rest) = line.strip_prefix("Operation ") {
|
||||
let mut parts = rest.splitn(2, ' ');
|
||||
let op_str = parts.next().unwrap_or("0");
|
||||
let remainder = parts.next().unwrap_or("");
|
||||
|
||||
let op: u32 = op_str.parse().unwrap_or(0);
|
||||
|
||||
// Tarih: "[2024-03-15 12:00:01]"
|
||||
let date = if let Some(start) = remainder.find('[') {
|
||||
if let Some(end) = remainder.find(']') {
|
||||
remainder[start+1..end].to_string()
|
||||
} else { String::new() }
|
||||
} else { String::new() };
|
||||
|
||||
// Tür + özet: ": install [vim, curl]"
|
||||
let (op_type, summary) = if let Some(colon) = remainder.rfind("]: ") {
|
||||
let after = &remainder[colon+3..];
|
||||
if let Some(sp) = after.find(' ') {
|
||||
(after[..sp].to_string(), after[sp+1..].to_string())
|
||||
} else {
|
||||
(after.to_string(), String::new())
|
||||
}
|
||||
} else { ("unknown".to_string(), remainder.to_string()) };
|
||||
|
||||
entries.push(PisiHistoryEntry { op, date, op_type, summary });
|
||||
}
|
||||
}
|
||||
// En yeni önce
|
||||
entries.sort_by(|a, b| b.op.cmp(&a.op));
|
||||
entries
|
||||
}
|
||||
|
||||
/// /mnt chroot içinde `pisi history` çalıştırır ve ayrıştırır.
|
||||
fn scan_pisi_history(&mut self) {
|
||||
self.pisi.entries.clear();
|
||||
self.pisi.result_msg = None;
|
||||
self.pisi.selected = None;
|
||||
|
||||
let out = std::process::Command::new("chroot")
|
||||
.args(["/mnt", "pisi", "history"])
|
||||
.output();
|
||||
|
||||
match out {
|
||||
Ok(o) => {
|
||||
let text = String::from_utf8_lossy(&o.stdout).to_string();
|
||||
let entries = Self::parse_pisi_history(&text);
|
||||
if entries.is_empty() {
|
||||
self.pisi.result_msg = Some(t!("rescue_pisi_history_empty").to_string());
|
||||
self.pisi.result_ok = Some(false);
|
||||
}
|
||||
self.pisi.entries = entries;
|
||||
}
|
||||
Err(e) => {
|
||||
self.pisi.result_msg = Some(format!("{}", e));
|
||||
self.pisi.result_ok = Some(false);
|
||||
}
|
||||
}
|
||||
self.pisi.scanned = true;
|
||||
}
|
||||
|
||||
/// `pisi takeback <op>` çalıştırır.
|
||||
fn run_takeback(&mut self, op: u32) {
|
||||
self.pisi.running = true;
|
||||
self.pisi.result_msg = Some(t!("rescue_pisi_takeback_start").to_string());
|
||||
self.pisi.result_ok = None;
|
||||
|
||||
let op_str = op.to_string();
|
||||
let out = std::process::Command::new("chroot")
|
||||
.args(["/mnt", "pisi", "takeback", &op_str])
|
||||
.output();
|
||||
|
||||
self.pisi.running = false;
|
||||
match out {
|
||||
Ok(o) if o.status.success() => {
|
||||
self.pisi.result_ok = Some(true);
|
||||
self.pisi.result_msg = Some(t!("rescue_pisi_history_ok").to_string());
|
||||
self.log.push(format!("✓ pisi takeback {} başarılı.", op));
|
||||
}
|
||||
Ok(o) => {
|
||||
let err = String::from_utf8_lossy(&o.stderr).trim().to_string();
|
||||
self.pisi.result_ok = Some(false);
|
||||
self.pisi.result_msg = Some(t!("rescue_pisi_history_err", err = err).to_string());
|
||||
self.log.push(format!("❌ pisi takeback {}: {}", op, err));
|
||||
}
|
||||
Err(e) => {
|
||||
self.pisi.result_ok = Some(false);
|
||||
self.pisi.result_msg = Some(t!("rescue_pisi_history_err", err = e.to_string()).to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── UI Panelleri ────────────────────────────────────────────────
|
||||
|
||||
fn show_chroot_panel(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Bölüm listesi
|
||||
ui.label(egui::RichText::new(t!("rescue_detected")).strong().color(theme::c_text()));
|
||||
ui.add_space(4.0);
|
||||
egui::ScrollArea::vertical()
|
||||
.id_source("rescue_partition_list")
|
||||
.max_height(130.0)
|
||||
.show(ui, |ui| {
|
||||
for (i, entry) in self.detected.iter().enumerate() {
|
||||
let is_selected = self.selected == Some(i);
|
||||
let label = egui::RichText::new(entry)
|
||||
.family(egui::FontFamily::Monospace)
|
||||
.color(if is_selected { theme::c_accent() } else { theme::c_text() });
|
||||
if ui.selectable_label(is_selected, label).clicked() {
|
||||
self.selected = Some(i);
|
||||
self.mount_done = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(10.0);
|
||||
|
||||
// İşlem butonları
|
||||
ui.horizontal(|ui| {
|
||||
// 1. Bağla
|
||||
if ui.add_enabled(
|
||||
self.selected.is_some() && !self.mount_done,
|
||||
theme::secondary_button("📂 /mnt'a Bağla"),
|
||||
).clicked() {
|
||||
self.mount_selected();
|
||||
}
|
||||
|
||||
// 2. Chroot
|
||||
if ui.add_enabled(
|
||||
self.mount_done,
|
||||
theme::secondary_button(&t!("rescue_chroot")),
|
||||
).clicked() {
|
||||
self.log.push(t!("rescue_chroot_start").to_string());
|
||||
match Self::run_rescue_cmd("chroot", &["/mnt", "/bin/bash", "-c", "echo 'chroot OK'"]) {
|
||||
Ok(msg) => self.log.push(format!("✓ {}", msg)),
|
||||
Err(e) => self.log.push(format!("❌ {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
// 3. GRUB yeniden yükle
|
||||
if ui.add_enabled(
|
||||
self.mount_done,
|
||||
theme::secondary_button(&t!("rescue_grub")),
|
||||
).clicked() {
|
||||
self.log.push(t!("rescue_grub_start").to_string());
|
||||
let boot_dev = state.bootloader_device.clone();
|
||||
let steps: &[(&str, &[&str])] = &[
|
||||
("mount", &["--bind", "/proc", "/mnt/proc"]),
|
||||
("mount", &["--bind", "/sys", "/mnt/sys"]),
|
||||
("mount", &["--bind", "/dev", "/mnt/dev"]),
|
||||
];
|
||||
for (cmd, args) in steps {
|
||||
match Self::run_rescue_cmd(cmd, args) {
|
||||
Ok(m) if !m.is_empty() => self.log.push(m),
|
||||
Ok(_) => {},
|
||||
Err(e) => self.log.push(format!("⚠ {}", e)),
|
||||
}
|
||||
}
|
||||
// grub2-install
|
||||
let grub_args: Vec<&str> = vec!["grub2-install", &boot_dev];
|
||||
match Self::run_rescue_cmd("chroot", &{
|
||||
let mut a: Vec<&str> = vec!["/mnt"];
|
||||
a.extend_from_slice(&grub_args);
|
||||
a
|
||||
}) {
|
||||
Ok(m) => self.log.push(format!("✓ grub2-install: {}", m)),
|
||||
Err(e) => self.log.push(format!("❌ grub2-install: {}", e)),
|
||||
}
|
||||
// grub2-mkconfig
|
||||
match Self::run_rescue_cmd("chroot", &["/mnt", "grub2-mkconfig", "-o", "/boot/grub2/grub.cfg"]) {
|
||||
Ok(m) => self.log.push(format!("✓ grub2-mkconfig: {}", m)),
|
||||
Err(e) => self.log.push(format!("❌ grub2-mkconfig: {}", e)),
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn show_pisi_panel(&mut self, ui: &mut egui::Ui) {
|
||||
ui.add_space(6.0);
|
||||
ui.label(
|
||||
egui::RichText::new(t!("rescue_pisi_history_desc"))
|
||||
.size(12.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
|
||||
if !self.mount_done {
|
||||
theme::warning_box(ui, "Önce 'Chroot & GRUB' sekmesinden bölümü /mnt'a bağlayın.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Tara butonu
|
||||
ui.horizontal(|ui| {
|
||||
if ui.add(theme::secondary_button(&t!("rescue_pisi_history_scan"))).clicked() {
|
||||
self.scan_pisi_history();
|
||||
}
|
||||
if self.pisi.scanned {
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{} işlem listelendi", self.pisi.entries.len()))
|
||||
.size(12.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if self.pisi.entries.is_empty() {
|
||||
if let Some(ref msg) = self.pisi.result_msg.clone() {
|
||||
ui.add_space(6.0);
|
||||
theme::warning_box(ui, msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Geçmiş tablosu
|
||||
egui::ScrollArea::vertical()
|
||||
.id_source("pisi_history_scroll")
|
||||
.max_height(200.0)
|
||||
.show(ui, |ui| {
|
||||
egui::Grid::new("pisi_history_grid")
|
||||
.num_columns(4)
|
||||
.spacing([12.0, 4.0])
|
||||
.striped(true)
|
||||
.show(ui, |ui| {
|
||||
// Başlık satırı
|
||||
ui.label(egui::RichText::new("#").strong().color(theme::c_text_dim()));
|
||||
ui.label(egui::RichText::new("Tarih").strong().color(theme::c_text_dim()));
|
||||
ui.label(egui::RichText::new("İşlem").strong().color(theme::c_text_dim()));
|
||||
ui.label(egui::RichText::new("Paketler").strong().color(theme::c_text_dim()));
|
||||
ui.end_row();
|
||||
|
||||
for (i, entry) in self.pisi.entries.iter().enumerate() {
|
||||
let is_selected = self.pisi.selected == Some(i);
|
||||
let row_color = if is_selected {
|
||||
theme::c_accent()
|
||||
} else {
|
||||
theme::c_text()
|
||||
};
|
||||
|
||||
let op_label = egui::RichText::new(entry.op.to_string())
|
||||
.family(egui::FontFamily::Monospace)
|
||||
.color(row_color);
|
||||
if ui.selectable_label(is_selected, op_label).clicked() {
|
||||
self.pisi.selected = Some(i);
|
||||
}
|
||||
|
||||
ui.label(egui::RichText::new(&entry.date).size(11.0).color(row_color));
|
||||
|
||||
// İşlem türüne renkli badge
|
||||
let type_color = match entry.op_type.as_str() {
|
||||
"install" => egui::Color32::from_rgb(80, 180, 80),
|
||||
"remove" => egui::Color32::from_rgb(200, 70, 70),
|
||||
"upgrade" => egui::Color32::from_rgb(70, 140, 220),
|
||||
_ => theme::c_text_dim(),
|
||||
};
|
||||
ui.colored_label(type_color, &entry.op_type);
|
||||
|
||||
// Özet — truncate
|
||||
let summary = if entry.summary.len() > 50 {
|
||||
format!("{}…", &entry.summary[..50])
|
||||
} else {
|
||||
entry.summary.clone()
|
||||
};
|
||||
ui.label(egui::RichText::new(summary).size(11.0).color(theme::c_text_dim()));
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(10.0);
|
||||
|
||||
// Geri al butonu
|
||||
let can_takeback = self.pisi.selected.is_some() && !self.pisi.running;
|
||||
if ui.add_enabled(can_takeback, theme::primary_button(&t!("rescue_pisi_takeback"))).clicked() {
|
||||
if let Some(idx) = self.pisi.selected {
|
||||
let op = self.pisi.entries[idx].op;
|
||||
self.run_takeback(op);
|
||||
}
|
||||
}
|
||||
|
||||
// Sonuç mesajı
|
||||
if let Some(ref msg) = self.pisi.result_msg.clone() {
|
||||
ui.add_space(6.0);
|
||||
match self.pisi.result_ok {
|
||||
Some(true) => theme::success_box(ui, msg),
|
||||
Some(false) => theme::error_box(ui, msg),
|
||||
None => { ui.label(msg); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstallerStep for RescueStep {
|
||||
fn name(&self) -> String { t!("rescue").to_string() }
|
||||
|
||||
fn on_enter(&mut self, _state: &mut GlobalState) {
|
||||
self.detect_installations();
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
theme::section_heading(ui, &t!("rescue_title"));
|
||||
ui.label(
|
||||
egui::RichText::new(t!("rescue_description"))
|
||||
.color(theme::c_text_dim())
|
||||
.size(13.0),
|
||||
);
|
||||
ui.add_space(10.0);
|
||||
|
||||
if self.detected.is_empty() {
|
||||
theme::warning_box(ui, &t!("rescue_no_installations"));
|
||||
ui.add_space(6.0);
|
||||
if ui.add(theme::secondary_button(&t!("rescue_scan"))).clicked() {
|
||||
self.detect_installations();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ─── Sekmeler ───────────────────────────────────────────────
|
||||
ui.horizontal(|ui| {
|
||||
let tab_labels = [
|
||||
("💻 Chroot & GRUB", 0usize),
|
||||
("📜 Pisi Geçmiş", 1usize),
|
||||
];
|
||||
for (label, idx) in &tab_labels {
|
||||
let active = self.tab == *idx;
|
||||
let rt = egui::RichText::new(*label)
|
||||
.strong()
|
||||
.color(if active { theme::c_accent() } else { theme::c_text_dim() });
|
||||
if ui.selectable_label(active, rt).clicked() {
|
||||
self.tab = *idx;
|
||||
}
|
||||
ui.separator();
|
||||
}
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
ui.add_space(4.0);
|
||||
|
||||
match self.tab {
|
||||
0 => self.show_chroot_panel(ui, state),
|
||||
1 => self.show_pisi_panel(ui),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
ui.add_space(12.0);
|
||||
|
||||
// Log alanı — her iki sekmede de görünür
|
||||
if !self.log.is_empty() {
|
||||
ui.separator();
|
||||
ui.add_space(4.0);
|
||||
ui.label(
|
||||
egui::RichText::new("Log")
|
||||
.size(11.0)
|
||||
.color(theme::c_text_dim()),
|
||||
);
|
||||
egui::ScrollArea::vertical()
|
||||
.id_source("rescue_log")
|
||||
.max_height(160.0)
|
||||
.stick_to_bottom(true)
|
||||
.show(ui, |ui| {
|
||||
egui::Frame::group(ui.style())
|
||||
.inner_margin(egui::Margin::same(8.0))
|
||||
.show(ui, |ui| {
|
||||
for line in &self.log {
|
||||
let color = if line.starts_with("✓") {
|
||||
theme::c_success()
|
||||
} else if line.starts_with("❌") {
|
||||
theme::c_error()
|
||||
} else if line.starts_with("⚠") {
|
||||
theme::c_warning()
|
||||
} else {
|
||||
theme::c_text_dim()
|
||||
};
|
||||
ui.colored_label(
|
||||
color,
|
||||
egui::RichText::new(line)
|
||||
.size(11.0)
|
||||
.family(egui::FontFamily::Monospace),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Geri dön butonu
|
||||
ui.add_space(8.0);
|
||||
if ui.add(theme::secondary_button(&t!("rescue_return"))).clicked() {
|
||||
state.rescue_mode = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn is_complete(&self, _state: &GlobalState) -> bool {
|
||||
false // Rescue modu her zaman "tamamlanmamış" — normal kuruluma dönmek için rescue_mode=false
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,39 @@ impl InstallerStep for SummaryStep {
|
||||
summary_row(ui, t!("summary_custom_partitions"), &plan_lines.join("\n"));
|
||||
}
|
||||
|
||||
// Tarih/Saat
|
||||
let dt_str = if state.use_ntp {
|
||||
t!("summary_ntp_enabled").to_string()
|
||||
} else {
|
||||
format!("{:04}-{:02}-{:02} {:02}:{:02} (NTP off)",
|
||||
state.manual_year, state.manual_month, state.manual_day,
|
||||
state.manual_hour, state.manual_minute)
|
||||
};
|
||||
summary_row(ui, t!("summary_datetime"), &dt_str);
|
||||
|
||||
// Bootloader
|
||||
let bl_str = format!("{} ({}s timeout{})",
|
||||
state.bootloader_device,
|
||||
state.bootloader_timeout,
|
||||
if state.bootloader_password.is_empty() { "" } else { ", password protected" }
|
||||
);
|
||||
summary_row(ui, t!("summary_bootloader"), &bl_str);
|
||||
|
||||
// Display Manager
|
||||
let dm_str = format!("{} / {} ({})",
|
||||
state.display_manager,
|
||||
state.desktop_environment,
|
||||
if state.autologin { t!("summary_autologin") } else { std::borrow::Cow::Borrowed("manual login") }
|
||||
);
|
||||
summary_row(ui, t!("summary_display_manager"), &dm_str);
|
||||
|
||||
let root_str = if state.root_password.is_empty() {
|
||||
t!("summary_root_disabled").to_string()
|
||||
} else {
|
||||
t!("summary_root_enabled").to_string()
|
||||
};
|
||||
summary_row(ui, t!("summary_root"), &root_str);
|
||||
|
||||
summary_row(ui, t!("summary_username"), &state.username);
|
||||
summary_row(ui, t!("summary_hostname"), &state.hostname);
|
||||
});
|
||||
|
||||
+171
-90
@@ -2,11 +2,13 @@ use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::installer::{GlobalState, InstallerStep};
|
||||
|
||||
/// Kullanıcı adı, şifre ve hostname ayarları adımı.
|
||||
/// Calamares'in Users modülüne karşılık gelir.
|
||||
/// Kullanıcı adı, şifre, hostname ve yönetici (root) şifresi ayarları adımı.
|
||||
pub struct UsersStep {
|
||||
show_password: bool,
|
||||
show_password_confirm: bool,
|
||||
show_root_password: bool,
|
||||
show_root_password_confirm: bool,
|
||||
use_same_for_admin: bool,
|
||||
}
|
||||
|
||||
impl Default for UsersStep {
|
||||
@@ -14,6 +16,9 @@ impl Default for UsersStep {
|
||||
Self {
|
||||
show_password: false,
|
||||
show_password_confirm: false,
|
||||
show_root_password: false,
|
||||
show_root_password_confirm: false,
|
||||
use_same_for_admin: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,110 +82,186 @@ impl InstallerStep for UsersStep {
|
||||
}
|
||||
|
||||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
ui.heading(t!("users_title"));
|
||||
ui.label(t!("users_description"));
|
||||
use crate::ui::theme;
|
||||
|
||||
theme::section_heading(ui, &t!("users_title"));
|
||||
ui.label(
|
||||
egui::RichText::new(t!("users_description"))
|
||||
.color(theme::c_text_dim())
|
||||
.size(13.0),
|
||||
);
|
||||
ui.add_space(12.0);
|
||||
|
||||
egui::Grid::new("users_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 10.0])
|
||||
// ─── Kullanıcı Bilgileri Grubu ──────────────────────────────────
|
||||
egui::Frame::group(ui.style())
|
||||
.fill(theme::c_bg_widget())
|
||||
.rounding(6.0)
|
||||
.inner_margin(egui::Margin::same(12.0))
|
||||
.show(ui, |ui| {
|
||||
// Kullanıcı adı
|
||||
ui.label(t!("username_label"));
|
||||
ui.horizontal(|ui| {
|
||||
ui.text_edit_singleline(&mut state.username);
|
||||
if !state.username.is_empty() {
|
||||
if is_valid_username(&state.username) {
|
||||
ui.colored_label(egui::Color32::from_rgb(80, 170, 80), "✓");
|
||||
} else {
|
||||
ui.colored_label(egui::Color32::from_rgb(200, 60, 40), "✗");
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
ui.set_width(ui.available_width());
|
||||
egui::Grid::new("users_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 10.0])
|
||||
.show(ui, |ui| {
|
||||
// Kullanıcı adı
|
||||
ui.label(egui::RichText::new(t!("username_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
ui.text_edit_singleline(&mut state.username);
|
||||
if !state.username.is_empty() {
|
||||
if is_valid_username(&state.username) {
|
||||
ui.colored_label(theme::c_success(), "✓");
|
||||
} else {
|
||||
ui.colored_label(theme::c_error(), "✗");
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Şifre
|
||||
ui.label(t!("password_label"));
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_password {
|
||||
ui.text_edit_singleline(&mut state.password);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.password).password(true));
|
||||
}
|
||||
if ui.small_button(if self.show_password { "🙈" } else { "👁" }).clicked() {
|
||||
self.show_password = !self.show_password;
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
// Şifre
|
||||
ui.label(egui::RichText::new(t!("password_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_password {
|
||||
ui.text_edit_singleline(&mut state.password);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.password).password(true));
|
||||
}
|
||||
if ui.small_button(if self.show_password { "🙈" } else { "👁" }).clicked() {
|
||||
self.show_password = !self.show_password;
|
||||
}
|
||||
if !state.password.is_empty() {
|
||||
let (label, color) = password_strength(&state.password);
|
||||
ui.colored_label(color, label);
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Şifre gücü göstergesi
|
||||
ui.label("");
|
||||
if !state.password.is_empty() {
|
||||
let (label, color) = password_strength(&state.password);
|
||||
ui.colored_label(color, label);
|
||||
}
|
||||
ui.end_row();
|
||||
// Şifre doğrulama
|
||||
ui.label(egui::RichText::new(t!("password_confirm_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_password_confirm {
|
||||
ui.text_edit_singleline(&mut state.password_confirm);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.password_confirm).password(true));
|
||||
}
|
||||
if ui.small_button(if self.show_password_confirm { "🙈" } else { "👁" }).clicked() {
|
||||
self.show_password_confirm = !self.show_password_confirm;
|
||||
}
|
||||
if !state.password_confirm.is_empty() {
|
||||
if state.password == state.password_confirm {
|
||||
ui.colored_label(theme::c_success(), "✓");
|
||||
} else {
|
||||
ui.colored_label(theme::c_error(), t!("passwords_no_match"));
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Şifre doğrulama
|
||||
ui.label(t!("password_confirm_label"));
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_password_confirm {
|
||||
ui.text_edit_singleline(&mut state.password_confirm);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.password_confirm).password(true));
|
||||
}
|
||||
if ui.small_button(if self.show_password_confirm { "🙈" } else { "👁" }).clicked() {
|
||||
self.show_password_confirm = !self.show_password_confirm;
|
||||
}
|
||||
if !state.password_confirm.is_empty() {
|
||||
if state.password == state.password_confirm {
|
||||
ui.colored_label(egui::Color32::from_rgb(80, 170, 80), "✓");
|
||||
} else {
|
||||
ui.colored_label(egui::Color32::from_rgb(200, 60, 40), t!("passwords_no_match"));
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Hostname
|
||||
ui.label(t!("hostname_label"));
|
||||
ui.horizontal(|ui| {
|
||||
// Username değişince hostname otomatik güncellenir (boşsa)
|
||||
if state.hostname.is_empty() && !state.username.is_empty() {
|
||||
state.hostname = format!("{}-pc", state.username);
|
||||
}
|
||||
ui.text_edit_singleline(&mut state.hostname);
|
||||
if !state.hostname.is_empty() {
|
||||
if is_valid_hostname(&state.hostname) {
|
||||
ui.colored_label(egui::Color32::from_rgb(80, 170, 80), "✓");
|
||||
} else {
|
||||
ui.colored_label(egui::Color32::from_rgb(200, 60, 40), "✗");
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
// Hostname
|
||||
ui.label(egui::RichText::new(t!("hostname_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
if state.hostname.is_empty() && !state.username.is_empty() {
|
||||
state.hostname = format!("{}-pc", state.username);
|
||||
}
|
||||
ui.text_edit_singleline(&mut state.hostname);
|
||||
if !state.hostname.is_empty() {
|
||||
if is_valid_hostname(&state.hostname) {
|
||||
ui.colored_label(theme::c_success(), "✓");
|
||||
} else {
|
||||
ui.colored_label(theme::c_error(), "✗");
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
});
|
||||
});
|
||||
|
||||
// Hata mesajları
|
||||
ui.add_space(14.0);
|
||||
|
||||
// ─── Yönetici (root) Ayarları ─────────────────────────────────────
|
||||
ui.checkbox(&mut self.use_same_for_admin, egui::RichText::new(t!("use_same_for_admin")).strong().color(theme::c_text()));
|
||||
|
||||
if self.use_same_for_admin {
|
||||
state.root_password = state.password.clone();
|
||||
state.root_password_confirm = state.password_confirm.clone();
|
||||
} else {
|
||||
ui.add_space(8.0);
|
||||
egui::Frame::group(ui.style())
|
||||
.fill(theme::c_bg_widget())
|
||||
.rounding(6.0)
|
||||
.inner_margin(egui::Margin::same(12.0))
|
||||
.show(ui, |ui| {
|
||||
ui.set_width(ui.available_width());
|
||||
ui.label(egui::RichText::new(t!("admin_description")).size(12.0).color(theme::c_text_dim()));
|
||||
ui.add_space(8.0);
|
||||
|
||||
egui::Grid::new("admin_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 10.0])
|
||||
.show(ui, |ui| {
|
||||
// Root şifresi
|
||||
ui.label(egui::RichText::new(t!("admin_password_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_root_password {
|
||||
ui.text_edit_singleline(&mut state.root_password);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.root_password).password(true));
|
||||
}
|
||||
if ui.small_button(if self.show_root_password { "🙈" } else { "👁" }).clicked() {
|
||||
self.show_root_password = !self.show_root_password;
|
||||
}
|
||||
if !state.root_password.is_empty() && state.root_password.len() < 4 {
|
||||
ui.colored_label(theme::c_error(), t!("admin_password_short"));
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// Şifre doğrulama
|
||||
ui.label(egui::RichText::new(t!("admin_password_confirm_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_root_password_confirm {
|
||||
ui.text_edit_singleline(&mut state.root_password_confirm);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(&mut state.root_password_confirm).password(true));
|
||||
}
|
||||
if ui.small_button(if self.show_root_password_confirm { "🙈" } else { "👁" }).clicked() {
|
||||
self.show_root_password_confirm = !self.show_root_password_confirm;
|
||||
}
|
||||
if !state.root_password_confirm.is_empty() {
|
||||
if state.root_password == state.root_password_confirm {
|
||||
ui.colored_label(theme::c_success(), "✓");
|
||||
} else {
|
||||
ui.colored_label(theme::c_error(), t!("passwords_no_match"));
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Hata mesajları gösterimi
|
||||
ui.add_space(8.0);
|
||||
if !state.username.is_empty() && !is_valid_username(&state.username) {
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(200, 60, 40),
|
||||
t!("username_invalid"),
|
||||
);
|
||||
ui.colored_label(theme::c_error(), t!("username_invalid"));
|
||||
}
|
||||
if !state.hostname.is_empty() && !is_valid_hostname(&state.hostname) {
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(200, 60, 40),
|
||||
t!("hostname_invalid"),
|
||||
);
|
||||
ui.colored_label(theme::c_error(), t!("hostname_invalid"));
|
||||
}
|
||||
}
|
||||
|
||||
fn is_complete(&self, state: &GlobalState) -> bool {
|
||||
is_valid_username(&state.username)
|
||||
let user_ok = is_valid_username(&state.username)
|
||||
&& is_valid_hostname(&state.hostname)
|
||||
&& !state.password.is_empty()
|
||||
&& state.password == state.password_confirm
|
||||
&& state.password.len() >= 4
|
||||
&& state.password == state.password_confirm;
|
||||
|
||||
if self.use_same_for_admin {
|
||||
user_ok
|
||||
} else {
|
||||
user_ok && (
|
||||
state.root_password.is_empty()
|
||||
|| (state.root_password.len() >= 4 && state.root_password == state.root_password_confirm)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+48
-57
@@ -5,6 +5,7 @@
|
||||
//! Masaüstü ortamına göre farklı slayt setleri yüklenebilir.
|
||||
|
||||
use eframe::egui;
|
||||
use std::collections::HashMap;
|
||||
use std::time::{Duration, Instant};
|
||||
use rust_i18n::t;
|
||||
use std::borrow::Cow;
|
||||
@@ -19,22 +20,34 @@ pub struct Slide {
|
||||
|
||||
/// Masaüstü ortamına göre slayt seti döner.
|
||||
/// ISO meta verisi ileride `/etc/livecd-desktop` gibi bir dosyadan okunabilir.
|
||||
pub fn slides_for_desktop(desktop: &str) -> Vec<Slide> {
|
||||
let mut slides = default_slides();
|
||||
let specific_slides = match desktop {
|
||||
"budgie" => budgie_slides(),
|
||||
"cinnamon" => cinnamon_slides(),
|
||||
"gnome" => gnome_slides(),
|
||||
"kde" | "plasma" => kde_slides(),
|
||||
"lxde" => lxde_slides(),
|
||||
"lxqt" => lxqt_slides(),
|
||||
"lumina" => lumina_slides(),
|
||||
"mate" => mate_slides(),
|
||||
"xfce" => xfce_slides(),
|
||||
_ => vec![],
|
||||
};
|
||||
slides.extend(specific_slides);
|
||||
slides
|
||||
pub fn slides_for_desktop(desktop: &str, branding_slides: &[crate::branding::SlideItem]) -> Vec<Slide> {
|
||||
if !branding_slides.is_empty() {
|
||||
branding_slides
|
||||
.iter()
|
||||
.filter(|item| item.desktop.is_empty() || item.desktop.to_lowercase() == desktop.to_lowercase())
|
||||
.map(|item| Slide {
|
||||
icon: Box::leak(item.icon.clone().into_boxed_str()),
|
||||
title: Cow::Owned(item.title.clone()),
|
||||
description: Cow::Owned(item.description.clone()),
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
let mut slides = default_slides();
|
||||
let specific_slides = match desktop {
|
||||
"budgie" => budgie_slides(),
|
||||
"cinnamon" => cinnamon_slides(),
|
||||
"gnome" => gnome_slides(),
|
||||
"kde" | "plasma" => kde_slides(),
|
||||
"lxde" => lxde_slides(),
|
||||
"lxqt" => lxqt_slides(),
|
||||
"lumina" => lumina_slides(),
|
||||
"mate" => mate_slides(),
|
||||
"xfce" => xfce_slides(),
|
||||
_ => vec![],
|
||||
};
|
||||
slides.extend(specific_slides);
|
||||
slides
|
||||
}
|
||||
}
|
||||
|
||||
fn default_slides() -> Vec<Slide> {
|
||||
@@ -175,7 +188,7 @@ fn lxde_slides() -> Vec<Slide> {
|
||||
description: t!("lxde_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "lxde_openbox_title",
|
||||
icon: "lxde_openbox",
|
||||
title: t!("lxde_openbox_title"),
|
||||
description: t!("lxde_openbox_description"),
|
||||
},
|
||||
@@ -185,7 +198,7 @@ fn lxde_slides() -> Vec<Slide> {
|
||||
description: t!("lxde_pcmanfm_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "lxde_lxpanel_title",
|
||||
icon: "lxde_lxpanel",
|
||||
title: t!("lxde_lxpanel_title"),
|
||||
description: t!("lxde_lxpanel_description"),
|
||||
},
|
||||
@@ -200,7 +213,7 @@ fn lxqt_slides() -> Vec<Slide> {
|
||||
description: t!("lxqt_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "lxqt_panel_title",
|
||||
icon: "lxqt_panel",
|
||||
title: t!("lxqt_panel_title"),
|
||||
description: t!("lxqt_panel_description"),
|
||||
},
|
||||
@@ -220,17 +233,17 @@ fn lumina_slides() -> Vec<Slide> {
|
||||
description: t!("lumina_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "lumina_applications_title",
|
||||
icon: "lumina_applications",
|
||||
title: t!("lumina_applications_title"),
|
||||
description: t!("lumina_applications_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "lumina_theme_title",
|
||||
icon: "lumina_theme",
|
||||
title: t!("lumina_theme_title"),
|
||||
description: t!("lumina_theme_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "lumina_panel_title",
|
||||
icon: "lumina_panel",
|
||||
title: t!("lumina_panel_title"),
|
||||
description: t!("lumina_panel_description"),
|
||||
},
|
||||
@@ -250,12 +263,12 @@ fn mate_slides() -> Vec<Slide> {
|
||||
description: t!("mate_caja_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "mate_settings_title",
|
||||
icon: "mate_settings",
|
||||
title: t!("mate_settings_title"),
|
||||
description: t!("mate_settings_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "mate_applications_title",
|
||||
icon: "mate_applications",
|
||||
title: t!("mate_applications_title"),
|
||||
description: t!("mate_applications_description"),
|
||||
},
|
||||
@@ -270,7 +283,7 @@ fn xfce_slides() -> Vec<Slide> {
|
||||
description: t!("xfce_description"),
|
||||
},
|
||||
Slide {
|
||||
icon: "xfce_panel_title",
|
||||
icon: "xfce_panel",
|
||||
title: t!("xfce_panel_title"),
|
||||
description: t!("xfce_panel_description"),
|
||||
},
|
||||
@@ -288,20 +301,23 @@ fn xfce_slides() -> Vec<Slide> {
|
||||
}
|
||||
|
||||
|
||||
// ─── Slayt gösterisi widget'ı ────────────────────────────────────
|
||||
// ─── Slayt gösterisi widget'ı ───────────────────────────────────────────
|
||||
|
||||
pub struct Slideshow {
|
||||
slides: Vec<Slide>,
|
||||
current: usize,
|
||||
last_advance: Instant,
|
||||
/// branding.toml'dan gelen ikon-adı → `file://` URI eşlemesi
|
||||
icons: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Slideshow {
|
||||
pub fn new(desktop: &str) -> Self {
|
||||
pub fn new(desktop: &str, icons: HashMap<String, String>, branding_slides: Vec<crate::branding::SlideItem>) -> Self {
|
||||
Self {
|
||||
slides: slides_for_desktop(desktop),
|
||||
slides: slides_for_desktop(desktop, &branding_slides),
|
||||
current: 0,
|
||||
last_advance: Instant::now(),
|
||||
icons,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,34 +337,9 @@ impl Slideshow {
|
||||
}
|
||||
|
||||
let slide = &self.slides[self.current];
|
||||
let is_dark = ui.visuals().dark_mode;
|
||||
|
||||
// Eşleşen slayt simgeleri için görsel belirle
|
||||
let image_source = match slide.icon {
|
||||
"budgie" => Some(egui::include_image!("../../assets/budgie.png")),
|
||||
"cinnamon" => Some(egui::include_image!("../../assets/cinnamon.png")),
|
||||
"community" => Some(egui::include_image!("../../assets/community.png")),
|
||||
"file_manager" => Some(egui::include_image!("../../assets/file_manager.png")),
|
||||
"gnome" => Some(egui::include_image!("../../assets/gnome.png")),
|
||||
"kde" => Some(egui::include_image!("../../assets/kde.png")),
|
||||
"lxqt" => Some(egui::include_image!("../../assets/lxqt.png")),
|
||||
"lumina" => Some(egui::include_image!("../../assets/lumina.png")),
|
||||
"lxde" => Some(egui::include_image!("../../assets/lxde.png")),
|
||||
"mate" => Some(egui::include_image!("../../assets/mate.png")),
|
||||
"pisilogo" => {
|
||||
if is_dark {
|
||||
Some(egui::include_image!("../../assets/pisi-logo-dark.png"))
|
||||
} else {
|
||||
Some(egui::include_image!("../../assets/pisi-logo-light.png"))
|
||||
}
|
||||
}
|
||||
"pisi" => Some(egui::include_image!("../../assets/pisi-software-center.png")),
|
||||
"pisi_speed" => Some(egui::include_image!("../../assets/pisi_speed.png")),
|
||||
"securety" => Some(egui::include_image!("../../assets/securety.png")),
|
||||
"xfce" => Some(egui::include_image!("../../assets/xfce.png")),
|
||||
"xfce_settings" => Some(egui::include_image!("../../assets/xfce_settings.png")),
|
||||
_ => None,
|
||||
};
|
||||
// İkona karşılık gelen URI'yi branding haritasından al
|
||||
let resolved_uri = self.icons.get(slide.icon).cloned();
|
||||
|
||||
egui::Frame::none()
|
||||
.fill(crate::ui::theme::c_bg_widget())
|
||||
@@ -358,9 +349,9 @@ impl Slideshow {
|
||||
ui.set_min_height(180.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
// Simge veya Görsel
|
||||
if let Some(img) = image_source {
|
||||
if let Some(uri) = resolved_uri {
|
||||
ui.add(
|
||||
egui::Image::new(img)
|
||||
egui::Image::from_uri(uri)
|
||||
.max_height(64.0)
|
||||
.rounding(egui::Rounding::same(8.0)),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user