Compare commits
1 Commits
master
...
yyt_branch
| Author | SHA1 | Date |
|---|---|---|
|
|
fd8fa214f4 | 2 years ago |
|
Before Width: | Height: | Size: 1.5 MiB |
@ -1,15 +0,0 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
||||
@ -1,414 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DBNavigator.Project.DatabaseBrowserManager">
|
||||
<autoscroll-to-editor value="false" />
|
||||
<autoscroll-from-editor value="true" />
|
||||
<show-object-properties value="true" />
|
||||
<loaded-nodes />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.DatabaseFileManager">
|
||||
<open-files />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.ExecutionManager">
|
||||
<retain-sticky-names value="false" />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.Settings">
|
||||
<connections />
|
||||
<browser-settings>
|
||||
<general>
|
||||
<display-mode value="TABBED" />
|
||||
<navigation-history-size value="100" />
|
||||
<show-object-details value="false" />
|
||||
</general>
|
||||
<filters>
|
||||
<object-type-filter>
|
||||
<object-type name="SCHEMA" enabled="true" />
|
||||
<object-type name="USER" enabled="true" />
|
||||
<object-type name="ROLE" enabled="true" />
|
||||
<object-type name="PRIVILEGE" enabled="true" />
|
||||
<object-type name="CHARSET" enabled="true" />
|
||||
<object-type name="TABLE" enabled="true" />
|
||||
<object-type name="VIEW" enabled="true" />
|
||||
<object-type name="MATERIALIZED_VIEW" enabled="true" />
|
||||
<object-type name="NESTED_TABLE" enabled="true" />
|
||||
<object-type name="COLUMN" enabled="true" />
|
||||
<object-type name="INDEX" enabled="true" />
|
||||
<object-type name="CONSTRAINT" enabled="true" />
|
||||
<object-type name="DATASET_TRIGGER" enabled="true" />
|
||||
<object-type name="DATABASE_TRIGGER" enabled="true" />
|
||||
<object-type name="SYNONYM" enabled="true" />
|
||||
<object-type name="SEQUENCE" enabled="true" />
|
||||
<object-type name="PROCEDURE" enabled="true" />
|
||||
<object-type name="FUNCTION" enabled="true" />
|
||||
<object-type name="PACKAGE" enabled="true" />
|
||||
<object-type name="TYPE" enabled="true" />
|
||||
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
|
||||
<object-type name="ARGUMENT" enabled="true" />
|
||||
<object-type name="DIMENSION" enabled="true" />
|
||||
<object-type name="CLUSTER" enabled="true" />
|
||||
<object-type name="DBLINK" enabled="true" />
|
||||
</object-type-filter>
|
||||
</filters>
|
||||
<sorting>
|
||||
<object-type name="COLUMN" sorting-type="NAME" />
|
||||
<object-type name="FUNCTION" sorting-type="NAME" />
|
||||
<object-type name="PROCEDURE" sorting-type="NAME" />
|
||||
<object-type name="ARGUMENT" sorting-type="POSITION" />
|
||||
<object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
|
||||
</sorting>
|
||||
<default-editors>
|
||||
<object-type name="VIEW" editor-type="SELECTION" />
|
||||
<object-type name="PACKAGE" editor-type="SELECTION" />
|
||||
<object-type name="TYPE" editor-type="SELECTION" />
|
||||
</default-editors>
|
||||
</browser-settings>
|
||||
<navigation-settings>
|
||||
<lookup-filters>
|
||||
<lookup-objects>
|
||||
<object-type name="SCHEMA" enabled="true" />
|
||||
<object-type name="USER" enabled="false" />
|
||||
<object-type name="ROLE" enabled="false" />
|
||||
<object-type name="PRIVILEGE" enabled="false" />
|
||||
<object-type name="CHARSET" enabled="false" />
|
||||
<object-type name="TABLE" enabled="true" />
|
||||
<object-type name="VIEW" enabled="true" />
|
||||
<object-type name="MATERIALIZED VIEW" enabled="true" />
|
||||
<object-type name="INDEX" enabled="true" />
|
||||
<object-type name="CONSTRAINT" enabled="true" />
|
||||
<object-type name="DATASET TRIGGER" enabled="true" />
|
||||
<object-type name="DATABASE TRIGGER" enabled="true" />
|
||||
<object-type name="SYNONYM" enabled="false" />
|
||||
<object-type name="SEQUENCE" enabled="true" />
|
||||
<object-type name="PROCEDURE" enabled="true" />
|
||||
<object-type name="FUNCTION" enabled="true" />
|
||||
<object-type name="PACKAGE" enabled="true" />
|
||||
<object-type name="TYPE" enabled="true" />
|
||||
<object-type name="DIMENSION" enabled="false" />
|
||||
<object-type name="CLUSTER" enabled="false" />
|
||||
<object-type name="DBLINK" enabled="true" />
|
||||
</lookup-objects>
|
||||
<force-database-load value="false" />
|
||||
<prompt-connection-selection value="true" />
|
||||
<prompt-schema-selection value="true" />
|
||||
</lookup-filters>
|
||||
</navigation-settings>
|
||||
<dataset-grid-settings>
|
||||
<general>
|
||||
<enable-zooming value="true" />
|
||||
<enable-column-tooltip value="true" />
|
||||
</general>
|
||||
<sorting>
|
||||
<nulls-first value="true" />
|
||||
<max-sorting-columns value="4" />
|
||||
</sorting>
|
||||
<audit-columns>
|
||||
<column-names value="" />
|
||||
<visible value="true" />
|
||||
<editable value="false" />
|
||||
</audit-columns>
|
||||
</dataset-grid-settings>
|
||||
<dataset-editor-settings>
|
||||
<text-editor-popup>
|
||||
<active value="false" />
|
||||
<active-if-empty value="false" />
|
||||
<data-length-threshold value="100" />
|
||||
<popup-delay value="1000" />
|
||||
</text-editor-popup>
|
||||
<values-actions-popup>
|
||||
<show-popup-button value="true" />
|
||||
<element-count-threshold value="1000" />
|
||||
<data-length-threshold value="250" />
|
||||
</values-actions-popup>
|
||||
<general>
|
||||
<fetch-block-size value="100" />
|
||||
<fetch-timeout value="30" />
|
||||
<trim-whitespaces value="true" />
|
||||
<convert-empty-strings-to-null value="true" />
|
||||
<select-content-on-cell-edit value="true" />
|
||||
<large-value-preview-active value="true" />
|
||||
</general>
|
||||
<filters>
|
||||
<prompt-filter-dialog value="true" />
|
||||
<default-filter-type value="BASIC" />
|
||||
</filters>
|
||||
<qualified-text-editor text-length-threshold="300">
|
||||
<content-types>
|
||||
<content-type name="Text" enabled="true" />
|
||||
<content-type name="Properties" enabled="true" />
|
||||
<content-type name="XML" enabled="true" />
|
||||
<content-type name="DTD" enabled="true" />
|
||||
<content-type name="HTML" enabled="true" />
|
||||
<content-type name="XHTML" enabled="true" />
|
||||
<content-type name="Java" enabled="true" />
|
||||
<content-type name="SQL" enabled="true" />
|
||||
<content-type name="PL/SQL" enabled="true" />
|
||||
<content-type name="JSON" enabled="true" />
|
||||
<content-type name="JSON5" enabled="true" />
|
||||
<content-type name="Groovy" enabled="true" />
|
||||
<content-type name="AIDL" enabled="true" />
|
||||
<content-type name="YAML" enabled="true" />
|
||||
<content-type name="Manifest" enabled="true" />
|
||||
</content-types>
|
||||
</qualified-text-editor>
|
||||
<record-navigation>
|
||||
<navigation-target value="VIEWER" />
|
||||
</record-navigation>
|
||||
</dataset-editor-settings>
|
||||
<code-editor-settings>
|
||||
<general>
|
||||
<show-object-navigation-gutter value="false" />
|
||||
<show-spec-declaration-navigation-gutter value="true" />
|
||||
<enable-spellchecking value="true" />
|
||||
<enable-reference-spellchecking value="false" />
|
||||
</general>
|
||||
<confirmations>
|
||||
<save-changes value="false" />
|
||||
<revert-changes value="true" />
|
||||
</confirmations>
|
||||
</code-editor-settings>
|
||||
<code-completion-settings>
|
||||
<filters>
|
||||
<basic-filter>
|
||||
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||
<filter-element type="OBJECT" id="role" selected="true" />
|
||||
<filter-element type="OBJECT" id="user" selected="true" />
|
||||
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||
<user-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</user-schema>
|
||||
<public-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="false" />
|
||||
<filter-element type="OBJECT" id="view" selected="false" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="false" />
|
||||
<filter-element type="OBJECT" id="index" selected="false" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="false" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="false" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="false" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="false" />
|
||||
<filter-element type="OBJECT" id="function" selected="false" />
|
||||
<filter-element type="OBJECT" id="package" selected="false" />
|
||||
<filter-element type="OBJECT" id="type" selected="false" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="false" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="false" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="false" />
|
||||
</public-schema>
|
||||
<any-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</any-schema>
|
||||
</basic-filter>
|
||||
<extended-filter>
|
||||
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||
<filter-element type="OBJECT" id="user" selected="true" />
|
||||
<filter-element type="OBJECT" id="role" selected="true" />
|
||||
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||
<user-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</user-schema>
|
||||
<public-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</public-schema>
|
||||
<any-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</any-schema>
|
||||
</extended-filter>
|
||||
</filters>
|
||||
<sorting enabled="true">
|
||||
<sorting-element type="RESERVED_WORD" id="keyword" />
|
||||
<sorting-element type="RESERVED_WORD" id="datatype" />
|
||||
<sorting-element type="OBJECT" id="column" />
|
||||
<sorting-element type="OBJECT" id="table" />
|
||||
<sorting-element type="OBJECT" id="view" />
|
||||
<sorting-element type="OBJECT" id="materialized view" />
|
||||
<sorting-element type="OBJECT" id="index" />
|
||||
<sorting-element type="OBJECT" id="constraint" />
|
||||
<sorting-element type="OBJECT" id="trigger" />
|
||||
<sorting-element type="OBJECT" id="synonym" />
|
||||
<sorting-element type="OBJECT" id="sequence" />
|
||||
<sorting-element type="OBJECT" id="procedure" />
|
||||
<sorting-element type="OBJECT" id="function" />
|
||||
<sorting-element type="OBJECT" id="package" />
|
||||
<sorting-element type="OBJECT" id="type" />
|
||||
<sorting-element type="OBJECT" id="dimension" />
|
||||
<sorting-element type="OBJECT" id="cluster" />
|
||||
<sorting-element type="OBJECT" id="dblink" />
|
||||
<sorting-element type="OBJECT" id="schema" />
|
||||
<sorting-element type="OBJECT" id="role" />
|
||||
<sorting-element type="OBJECT" id="user" />
|
||||
<sorting-element type="RESERVED_WORD" id="function" />
|
||||
<sorting-element type="RESERVED_WORD" id="parameter" />
|
||||
</sorting>
|
||||
<format>
|
||||
<enforce-code-style-case value="true" />
|
||||
</format>
|
||||
</code-completion-settings>
|
||||
<execution-engine-settings>
|
||||
<statement-execution>
|
||||
<fetch-block-size value="100" />
|
||||
<execution-timeout value="20" />
|
||||
<debug-execution-timeout value="600" />
|
||||
<focus-result value="false" />
|
||||
<prompt-execution value="false" />
|
||||
</statement-execution>
|
||||
<script-execution>
|
||||
<command-line-interfaces />
|
||||
<execution-timeout value="300" />
|
||||
</script-execution>
|
||||
<method-execution>
|
||||
<execution-timeout value="30" />
|
||||
<debug-execution-timeout value="600" />
|
||||
<parameter-history-size value="10" />
|
||||
</method-execution>
|
||||
</execution-engine-settings>
|
||||
<operation-settings>
|
||||
<transactions>
|
||||
<uncommitted-changes>
|
||||
<on-project-close value="ASK" />
|
||||
<on-disconnect value="ASK" />
|
||||
<on-autocommit-toggle value="ASK" />
|
||||
</uncommitted-changes>
|
||||
<multiple-uncommitted-changes>
|
||||
<on-commit value="ASK" />
|
||||
<on-rollback value="ASK" />
|
||||
</multiple-uncommitted-changes>
|
||||
</transactions>
|
||||
<session-browser>
|
||||
<disconnect-session value="ASK" />
|
||||
<kill-session value="ASK" />
|
||||
<reload-on-filter-change value="false" />
|
||||
</session-browser>
|
||||
<compiler>
|
||||
<compile-type value="KEEP" />
|
||||
<compile-dependencies value="ASK" />
|
||||
<always-show-controls value="false" />
|
||||
</compiler>
|
||||
<debugger>
|
||||
<debugger-type value="ASK" />
|
||||
</debugger>
|
||||
</operation-settings>
|
||||
<ddl-file-settings>
|
||||
<extensions>
|
||||
<mapping file-type-id="VIEW" extensions="vw" />
|
||||
<mapping file-type-id="TRIGGER" extensions="trg" />
|
||||
<mapping file-type-id="PROCEDURE" extensions="prc" />
|
||||
<mapping file-type-id="FUNCTION" extensions="fnc" />
|
||||
<mapping file-type-id="PACKAGE" extensions="pkg" />
|
||||
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
|
||||
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
|
||||
<mapping file-type-id="TYPE" extensions="tpe" />
|
||||
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
|
||||
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
|
||||
</extensions>
|
||||
<general>
|
||||
<lookup-ddl-files value="true" />
|
||||
<create-ddl-files value="false" />
|
||||
<synchronize-ddl-files value="true" />
|
||||
<use-qualified-names value="false" />
|
||||
<make-scripts-rerunnable value="true" />
|
||||
</general>
|
||||
</ddl-file-settings>
|
||||
<general-settings>
|
||||
<regional-settings>
|
||||
<date-format value="MEDIUM" />
|
||||
<number-format value="UNGROUPED" />
|
||||
<locale value="SYSTEM_DEFAULT" />
|
||||
<use-custom-formats value="false" />
|
||||
</regional-settings>
|
||||
<environment>
|
||||
<environment-types>
|
||||
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
|
||||
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
|
||||
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
|
||||
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
|
||||
</environment-types>
|
||||
<visibility-settings>
|
||||
<connection-tabs value="true" />
|
||||
<dialog-headers value="true" />
|
||||
<object-editor-tabs value="true" />
|
||||
<script-editor-tabs value="false" />
|
||||
<execution-result-tabs value="true" />
|
||||
</visibility-settings>
|
||||
</environment>
|
||||
</general-settings>
|
||||
</component>
|
||||
</project>
|
||||
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="jbr-17" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@ -1,41 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.22" />
|
||||
</component>
|
||||
</project>
|
||||
@ -1,9 +0,0 @@
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -1 +0,0 @@
|
||||
/build
|
||||
@ -1,92 +0,0 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.example.fruitandvegetableguide'
|
||||
compileSdk 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.example.fruitandvegetableguide"
|
||||
minSdk 24
|
||||
targetSdk 34
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
useSupportLibrary true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion '1.4.8'
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.compose.foundation:foundation:1.0.0"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07"
|
||||
//用于compose权限的使用
|
||||
implementation("com.google.accompanist:accompanist-permissions:0.31.0-alpha")
|
||||
//闪光
|
||||
implementation("com.google.accompanist:accompanist-placeholder-material:0.31.0-alpha")
|
||||
implementation("io.coil-kt:coil-compose:2.2.2")
|
||||
//gson
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
|
||||
implementation("androidx.navigation:navigation-compose:2.5.3")
|
||||
|
||||
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||
implementation "androidx.core:core-ktx:1.10.1"
|
||||
implementation "com.google.android.material:material:1.9.0"
|
||||
implementation 'androidx.core:core-ktx:+'
|
||||
implementation 'androidx.core:core-ktx:+'
|
||||
implementation 'androidx.core:core-ktx:+'
|
||||
implementation 'androidx.core:core-ktx:+'
|
||||
implementation files('libs\\jtds-1.3.1.jar')
|
||||
|
||||
def composeBom = platform('androidx.compose:compose-bom:2023.08.00')
|
||||
implementation(composeBom)
|
||||
androidTestImplementation(composeBom)
|
||||
|
||||
implementation("androidx.compose.material3:material3")
|
||||
implementation("androidx.compose.material:material-icons-extended")
|
||||
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"
|
||||
implementation("androidx.activity:activity-compose:1.7.2")
|
||||
implementation 'androidx.core:core-ktx:1.10.1'
|
||||
implementation "androidx.window:window:1.1.0"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1"
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@ -1,20 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.example.fruitandvegetableguide",
|
||||
"variantName": "release",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"attributes": [],
|
||||
"versionCode": 1,
|
||||
"versionName": "1.0",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File"
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package com.example.fruitandvegetableguide
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.example.fruitandvegetableguide", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
package com.example.fruitandvegetableguide
|
||||
|
||||
|
||||
// 每个界面路由接口
|
||||
interface Destinations {
|
||||
val route: String
|
||||
}
|
||||
|
||||
//接口实现
|
||||
object Login : Destinations {
|
||||
override val route: String = "login"
|
||||
}
|
||||
|
||||
object Register : Destinations {
|
||||
override val route: String = "register"
|
||||
}
|
||||
|
||||
object Main : Destinations {
|
||||
override val route: String = "main"
|
||||
}
|
||||
|
||||
object Search : Destinations {
|
||||
override val route: String = "search"
|
||||
}
|
||||
|
||||
object PostDetail : Destinations {
|
||||
override val route: String = "postDetail"
|
||||
}
|
||||
|
||||
object GuideDetail : Destinations {
|
||||
override val route: String = "guideDetail"
|
||||
}
|
||||
|
||||
object User : Destinations {
|
||||
override val route: String = "user"
|
||||
}
|
||||
|
||||
object MyPost : Destinations {
|
||||
override val route: String = "myPost"
|
||||
}
|
||||
|
||||
object Photograph : Destinations {
|
||||
override val route: String = "photograph"
|
||||
}
|
||||
|
||||
object RecognizeResult : Destinations {
|
||||
override val route: String = "recognizeResult"
|
||||
}
|
||||
|
||||
object Guide : Destinations {
|
||||
override val route: String = "guide"
|
||||
}
|
||||
|
||||
object Community : Destinations {
|
||||
override val route: String = "community"
|
||||
}
|
||||
|
||||
object PostEdit : Destinations {
|
||||
override val route: String = "postEdit"
|
||||
}
|
||||
|
||||
//val Screens = listOf(Login, Register, Main)
|
||||
@ -1,218 +0,0 @@
|
||||
package com.example.fruitandvegetableguide
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.example.fruitandvegetableguide.ui.community.CommunityScreen
|
||||
import com.example.fruitandvegetableguide.ui.community.PostDetailScreen
|
||||
import com.example.fruitandvegetableguide.ui.community.PostEditScreen
|
||||
import com.example.fruitandvegetableguide.ui.guide.GuideDetailScreen
|
||||
import com.example.fruitandvegetableguide.ui.guide.GuideScreen
|
||||
import com.example.fruitandvegetableguide.ui.imgrecognition.PhotographScreen
|
||||
import com.example.fruitandvegetableguide.ui.imgrecognition.RecognizeResultScreen
|
||||
import com.example.fruitandvegetableguide.ui.login.LoginScreen
|
||||
import com.example.fruitandvegetableguide.ui.main.MainScreen
|
||||
import com.example.fruitandvegetableguide.ui.register.RegisterScreen
|
||||
import com.example.fruitandvegetableguide.ui.search.SearchScreen
|
||||
import com.example.fruitandvegetableguide.ui.user.MyPostScreen
|
||||
import com.example.fruitandvegetableguide.ui.user.UserScreen
|
||||
|
||||
@Composable
|
||||
fun NavHost(
|
||||
navController: NavHostController,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = Login.route,
|
||||
modifier = modifier
|
||||
) {
|
||||
//登录页路由
|
||||
composable(route = Login.route) {
|
||||
LoginScreen(
|
||||
onClickToRegister = { navController.navigateSingleTopTo(Register.route) },
|
||||
onClickToMain = { userid -> navController.navigateSingleTopTo("${Main.route}/${userid}") }//传出userid
|
||||
)
|
||||
}
|
||||
//注册页路由
|
||||
composable(route = Register.route) {
|
||||
RegisterScreen(
|
||||
onClickBack = { navController.popBackStack() }
|
||||
)
|
||||
}
|
||||
//首页路由
|
||||
composable(
|
||||
route = "${Main.route}/{userid}",
|
||||
arguments = listOf(
|
||||
navArgument("userid") {
|
||||
type = NavType.IntType
|
||||
nullable = false
|
||||
}
|
||||
)
|
||||
) {
|
||||
val userid = it.arguments?.getInt("userid")//接收userid
|
||||
MainScreen(
|
||||
userid = userid,
|
||||
onClickToSearch = { search -> navController.navigateSingleTopTo("${Search.route}/${search}") },
|
||||
onClickToUser = { navController.navigateSingleTopTo("${User.route}/${userid}") },
|
||||
onClickToPhotograph = { navController.navigateSingleTopTo(Photograph.route) },
|
||||
onClickToGuide = { navController.navigateSingleTopTo(Guide.route) },
|
||||
onClickToCommunity = { navController.navigateSingleTopTo("${Community.route}/${userid}") },
|
||||
onClickToGuideDetail = { guideId -> navController.navigateSingleTopTo("${GuideDetail.route}/${guideId}") },
|
||||
onClickToPostDetail = { postId -> navController.navigateSingleTopTo("${PostDetail.route}/${postId}") }
|
||||
)
|
||||
}
|
||||
//搜索页路由
|
||||
composable(
|
||||
route = "${Search.route}/{search}",
|
||||
arguments = listOf(
|
||||
navArgument("search") {
|
||||
type = NavType.StringType
|
||||
nullable = false
|
||||
}
|
||||
)
|
||||
) {
|
||||
val search = it.arguments?.getString("search")
|
||||
SearchScreen(
|
||||
search = search,
|
||||
onClickBack = { navController.popBackStack() },
|
||||
onClickToGuideDetail = { guideId -> navController.navigateSingleTopTo("${GuideDetail.route}/${guideId}") },
|
||||
onClickToPostDetail = { postId -> navController.navigateSingleTopTo("${PostDetail.route}/${postId}") },
|
||||
)
|
||||
}
|
||||
//指南详情页路由
|
||||
composable(
|
||||
route = "${GuideDetail.route}/{guideId}",
|
||||
arguments = listOf(
|
||||
navArgument("guideId") {
|
||||
type = NavType.IntType
|
||||
nullable = false
|
||||
}
|
||||
)
|
||||
) {
|
||||
val guideId = it.arguments?.getInt("guideId")
|
||||
GuideDetailScreen(
|
||||
guideId = guideId,
|
||||
onClickBack = { navController.popBackStack() })
|
||||
}
|
||||
//帖子详情页路由
|
||||
composable(
|
||||
route = "${PostDetail.route}/{postId}",
|
||||
arguments = listOf(
|
||||
navArgument("postId") {
|
||||
type = NavType.IntType
|
||||
nullable = false
|
||||
}
|
||||
)
|
||||
) {
|
||||
val postId = it.arguments?.getInt("postId") //接收post的属性列表
|
||||
PostDetailScreen(
|
||||
postId = postId,
|
||||
onClickBack = { navController.popBackStack() }
|
||||
)
|
||||
}
|
||||
//用户页路由
|
||||
composable(
|
||||
route = "${User.route}/{userid}",
|
||||
arguments = listOf(
|
||||
navArgument("userid") {
|
||||
type = NavType.IntType
|
||||
nullable = false
|
||||
}
|
||||
)) {
|
||||
val userid = it.arguments?.getInt("userid")//接收userid
|
||||
UserScreen(
|
||||
userid = userid,
|
||||
onClickToMain = { navController.popBackStack() },
|
||||
onClickToMyPost = { navController.navigateSingleTopTo("${MyPost.route}/${userid}") },
|
||||
onClickToPhotograph = { navController.navigateSingleTopTo(Photograph.route) }
|
||||
)
|
||||
}
|
||||
//我的帖子页面路由
|
||||
composable(route = "${MyPost.route}/{userid}",
|
||||
arguments = listOf(
|
||||
navArgument("userid") {
|
||||
type = NavType.IntType
|
||||
nullable = false
|
||||
}
|
||||
)) {
|
||||
val userid = it.arguments?.getInt("userid")//接收userid
|
||||
MyPostScreen(userid = userid, onClickBack = { navController.popBackStack() })
|
||||
}
|
||||
//拍照页路由
|
||||
composable(route = Photograph.route) {
|
||||
PhotographScreen(
|
||||
onClickBack = { navController.popBackStack() },
|
||||
onClickToRecognizeResult = { localImgPath ->
|
||||
navController.navigateSingleTopTo(
|
||||
"${RecognizeResult.route}/${localImgPath}"
|
||||
)
|
||||
})
|
||||
}
|
||||
//识别结果页路由
|
||||
composable(
|
||||
route = "${RecognizeResult.route}/{localImgPath}",
|
||||
arguments = listOf(
|
||||
navArgument("localImgPath") {
|
||||
type = NavType.StringType
|
||||
nullable = false
|
||||
})
|
||||
) {
|
||||
val localImgPath = it.arguments?.getString("localImgPath")
|
||||
RecognizeResultScreen(
|
||||
transPath = localImgPath,
|
||||
onClickBack = { navController.popBackStack() })
|
||||
}
|
||||
//指南页路由
|
||||
composable(route = Guide.route) {
|
||||
GuideScreen(
|
||||
onClickToSearch = { search -> navController.navigateSingleTopTo("${Search.route}/${search}") },
|
||||
onClickToGuideDetail = { guideId -> navController.navigateSingleTopTo("${GuideDetail.route}/${guideId}") },
|
||||
onClickBack = { navController.popBackStack() }
|
||||
)
|
||||
}
|
||||
//社区页路由
|
||||
composable(
|
||||
route = "${Community.route}/{userid}",
|
||||
arguments = listOf(
|
||||
navArgument("userid") {
|
||||
type = NavType.IntType
|
||||
nullable = false
|
||||
}
|
||||
)
|
||||
) {
|
||||
val userid = it.arguments?.getInt("userid")//接收userid
|
||||
CommunityScreen(
|
||||
userid = userid,
|
||||
onClickToSearch = { search -> navController.navigateSingleTopTo("${Search.route}/${search}") },
|
||||
onClickToPostDetail = { postId -> navController.navigateSingleTopTo("${PostDetail.route}/${postId}") },
|
||||
onClickToPostEdit = { navController.navigateSingleTopTo("${PostEdit.route}/${userid}") },
|
||||
onClickBack = { navController.popBackStack() }
|
||||
)
|
||||
}
|
||||
//帖子编辑页路由
|
||||
composable(
|
||||
route = "${PostEdit.route}/{userid}",
|
||||
arguments = listOf(
|
||||
navArgument("userid") {
|
||||
type = NavType.IntType
|
||||
nullable = false
|
||||
}
|
||||
)
|
||||
) {
|
||||
val userid = it.arguments?.getInt("userid")//接收userid
|
||||
PostEditScreen(
|
||||
userid = userid,
|
||||
onClickBack = { navController.popBackStack() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//如果栈中已经包含了指定要跳转的界面,那么只会保留一个
|
||||
fun NavHostController.navigateSingleTopTo(route: String) =
|
||||
this.navigate(route) { launchSingleTop = true }
|
||||
@ -1,12 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.data.local
|
||||
|
||||
import com.example.fruitandvegetableguide.data.Account
|
||||
|
||||
//本地用户测试数据
|
||||
object LocalAccountsDataProvider {
|
||||
val allUserAccounts = mutableListOf(
|
||||
Account(1,"aaa","123456"),
|
||||
Account(2,"bbb","123456"),
|
||||
Account(3,"ccc","123456")
|
||||
)
|
||||
}
|
||||
@ -1,206 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.community
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.ArrowForwardIos
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.data.Post
|
||||
import com.example.fruitandvegetableguide.utils.postListInit
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun CommunityScreen(
|
||||
userid: Int? = 1,
|
||||
onClickToSearch: (search: String) -> Unit = {},
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
onClickToPostEdit: (userid: Int) -> Unit = {},
|
||||
onClickBack: () -> Unit = {},
|
||||
) {
|
||||
val postList = postListInit()
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = "社区",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
bottomBar = {
|
||||
BottomAppBar(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Spacer(modifier = Modifier.requiredWidth(30.dp))
|
||||
Button(onClick = { onClickToPostEdit(userid ?: 1) }) {
|
||||
Text(text = "分享我的经验")
|
||||
}
|
||||
Spacer(modifier = Modifier.requiredWidth(30.dp))
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Column {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.requiredHeight(60.dp)
|
||||
)
|
||||
SearchBar(onClickToSearch = onClickToSearch)
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.requiredHeight(10.dp)
|
||||
.padding(it)
|
||||
)
|
||||
|
||||
Posts(postsList = postList, onClickToPostDetail = onClickToPostDetail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//搜索框
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToSearch: (search: String) -> Unit
|
||||
) {
|
||||
var search by remember {
|
||||
mutableStateOf("")
|
||||
}
|
||||
TextField(
|
||||
value = search, onValueChange = { str -> search = str },
|
||||
leadingIcon = {
|
||||
IconButton(onClick = {
|
||||
//路由不能传递空字符串
|
||||
if (search == "") {
|
||||
search = " "
|
||||
}
|
||||
onClickToSearch(search)
|
||||
}) {
|
||||
Icon(imageVector = Icons.Default.Search, contentDescription = null)
|
||||
}
|
||||
},
|
||||
colors = TextFieldDefaults.colors(
|
||||
unfocusedContainerColor = MaterialTheme.colorScheme.surface,
|
||||
focusedContainerColor = MaterialTheme.colorScheme.surface
|
||||
),
|
||||
placeholder = { Text(text = "搜索") },
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(56.dp)
|
||||
)
|
||||
}
|
||||
|
||||
//帖子列表的显示
|
||||
@Composable
|
||||
fun Posts(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
postsList: List<Post>
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
items(items = postsList) { post ->
|
||||
Post(post = post, onClickToPostDetail = onClickToPostDetail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//单个帖子的显示
|
||||
@Composable
|
||||
fun Post(
|
||||
post: Post,
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
) {
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary),
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioMediumBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Text(
|
||||
text = post.title,
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(text = post.labels)
|
||||
}
|
||||
Button(onClick = {
|
||||
onClickToPostDetail(post.id)
|
||||
}) {
|
||||
Icon(imageVector = Icons.Filled.ArrowForwardIos, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.community
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.data.Post
|
||||
import com.example.fruitandvegetableguide.utils.getPostByPostId
|
||||
|
||||
@Composable
|
||||
fun PostDetailScreen(
|
||||
postId: Int? = 1,
|
||||
onClickBack: () -> Unit
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
val post: Post = getPostByPostId(postId ?: 1)
|
||||
Column(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState)) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = post.title,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "标签",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(
|
||||
text = post.labels,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "内容",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(
|
||||
text = post.content
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,127 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.community
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.utils.postInsert
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun PostEditScreen(
|
||||
userid: Int? = 1,
|
||||
onClickBack: () -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = "编辑",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
})
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
|
||||
var title by remember { mutableStateOf("") }
|
||||
var labels by remember { mutableStateOf("") }
|
||||
var content by remember { mutableStateOf("") }
|
||||
|
||||
Text(
|
||||
text = "标题",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
TextField(
|
||||
value = title,
|
||||
onValueChange = { str -> title = str },
|
||||
modifier = Modifier.fillMaxWidth(1f)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "标签",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
TextField(
|
||||
value = labels,
|
||||
onValueChange = { str -> labels = str },
|
||||
modifier = Modifier.fillMaxWidth(1f)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "内容",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
TextField(
|
||||
value = content,
|
||||
onValueChange = { str -> content = str },
|
||||
modifier = Modifier.fillMaxWidth(1f)
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier.padding(vertical = 24.dp),
|
||||
onClick = {
|
||||
if (
|
||||
title != "" && labels != "" && content != "" && postInsert(
|
||||
userid = userid ?: 1,
|
||||
title = title,
|
||||
labels = labels,
|
||||
content = content
|
||||
)
|
||||
) {
|
||||
Toast.makeText(context, "发布成功", Toast.LENGTH_SHORT).show()
|
||||
onClickBack()
|
||||
} else {
|
||||
Toast.makeText(context, "发布失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("发布")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,104 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.guide
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.data.Guide
|
||||
import com.example.fruitandvegetableguide.utils.getGuideByGuideId
|
||||
|
||||
//@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun GuideDetailScreen(
|
||||
guideId: Int? = 1,
|
||||
onClickBack: () -> Unit
|
||||
) {
|
||||
val guide: Guide = getGuideByGuideId(guideId ?: 1)
|
||||
val scrollState = rememberScrollState()
|
||||
Column(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState)) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = guide.kind,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
})
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "挑选方法",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(
|
||||
text = guide.identify,
|
||||
)
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "适宜人群",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(
|
||||
text = guide.suitable,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "食用禁忌",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(
|
||||
text = guide.taboo,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "营养价值",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(
|
||||
text = guide.nutritiveValue
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Text(
|
||||
text = "推荐菜品",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(
|
||||
text = guide.recommendedMenu,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,166 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.guide
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.ArrowForwardIos
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.data.Guide
|
||||
import com.example.fruitandvegetableguide.utils.guideListInit
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun GuideScreen(
|
||||
onClickToSearch: (search: String) -> Unit = {},
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
onClickBack: () -> Unit = {},
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = "指南",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
})
|
||||
SearchBar(onClickToSearch = onClickToSearch)
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Guides(onClickToGuideDetail = onClickToGuideDetail)
|
||||
}
|
||||
}
|
||||
|
||||
//搜索框
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToSearch: (search: String) -> Unit
|
||||
) {
|
||||
var search by remember {
|
||||
mutableStateOf("")
|
||||
}
|
||||
TextField(
|
||||
value = search, onValueChange = { str -> search = str },
|
||||
leadingIcon = {
|
||||
IconButton(onClick = {
|
||||
//路由不能传递空字符串
|
||||
if (search == "") {
|
||||
search = " "
|
||||
}
|
||||
onClickToSearch(search)
|
||||
}) {
|
||||
Icon(imageVector = Icons.Default.Search, contentDescription = null)
|
||||
}
|
||||
},
|
||||
colors = TextFieldDefaults.colors(
|
||||
unfocusedContainerColor = MaterialTheme.colorScheme.surface,
|
||||
focusedContainerColor = MaterialTheme.colorScheme.surface
|
||||
),
|
||||
placeholder = { Text(text = "搜索") },
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(56.dp)
|
||||
)
|
||||
}
|
||||
|
||||
//指南列表的显示
|
||||
@Composable
|
||||
fun Guides(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {}
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
items(guideListInit()) { guide ->
|
||||
Guide(guide = guide, onClickToGuideDetail = onClickToGuideDetail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//单个指南的显示
|
||||
@Composable
|
||||
fun Guide(
|
||||
guide: Guide,
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {}
|
||||
) {
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary),
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioMediumBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Text(
|
||||
text = guide.kind,
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(text = guide.suitable)
|
||||
}
|
||||
Button(onClick = {
|
||||
onClickToGuideDetail(guide.id)
|
||||
}) {
|
||||
Icon(imageVector = Icons.Filled.ArrowForwardIos, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.imgrecognition.bauduai;
|
||||
|
||||
/**
|
||||
* Base64 工具类
|
||||
*/
|
||||
public class Base64Util {
|
||||
private static final char last2byte = (char) Integer.parseInt("00000011", 2);
|
||||
private static final char last4byte = (char) Integer.parseInt("00001111", 2);
|
||||
private static final char last6byte = (char) Integer.parseInt("00111111", 2);
|
||||
private static final char lead6byte = (char) Integer.parseInt("11111100", 2);
|
||||
private static final char lead4byte = (char) Integer.parseInt("11110000", 2);
|
||||
private static final char lead2byte = (char) Integer.parseInt("11000000", 2);
|
||||
private static final char[] encodeTable = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
|
||||
|
||||
public Base64Util() {
|
||||
}
|
||||
|
||||
public static String encode(byte[] from) {
|
||||
StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3);
|
||||
int num = 0;
|
||||
char currentByte = 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < from.length; ++i) {
|
||||
for (num %= 8; num < 8; num += 6) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
currentByte = (char) (from[i] & lead6byte);
|
||||
currentByte = (char) (currentByte >>> 2);
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
default:
|
||||
break;
|
||||
case 2:
|
||||
currentByte = (char) (from[i] & last6byte);
|
||||
break;
|
||||
case 4:
|
||||
currentByte = (char) (from[i] & last4byte);
|
||||
currentByte = (char) (currentByte << 2);
|
||||
if (i + 1 < from.length) {
|
||||
currentByte = (char) (currentByte | (from[i + 1] & lead2byte) >>> 6);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
currentByte = (char) (from[i] & last2byte);
|
||||
currentByte = (char) (currentByte << 4);
|
||||
if (i + 1 < from.length) {
|
||||
currentByte = (char) (currentByte | (from[i + 1] & lead4byte) >>> 4);
|
||||
}
|
||||
}
|
||||
|
||||
to.append(encodeTable[currentByte]);
|
||||
}
|
||||
}
|
||||
|
||||
if (to.length() % 4 != 0) {
|
||||
for (i = 4 - to.length() % 4; i > 0; --i) {
|
||||
to.append("=");
|
||||
}
|
||||
}
|
||||
|
||||
return to.toString();
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
|
||||
*/
|
||||
package com.example.fruitandvegetableguide.ui.imgrecognition.bauduai;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Json工具类.
|
||||
*/
|
||||
public class GsonUtils {
|
||||
private static Gson gson = new GsonBuilder().create();
|
||||
|
||||
public static String toJson(Object value) {
|
||||
return gson.toJson(value);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Class<T> classOfT) throws JsonParseException {
|
||||
return gson.fromJson(json, classOfT);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Type typeOfT) throws JsonParseException {
|
||||
return (T) gson.fromJson(json, typeOfT);
|
||||
}
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.imgrecognition.bauduai;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* http 工具类
|
||||
*/
|
||||
public class HttpUtil {
|
||||
|
||||
public static String post(String requestUrl, String accessToken, String params)
|
||||
throws Exception {
|
||||
String contentType = "application/x-www-form-urlencoded";
|
||||
return HttpUtil.post(requestUrl, accessToken, contentType, params);
|
||||
}
|
||||
|
||||
public static String post(String requestUrl, String accessToken, String contentType, String params)
|
||||
throws Exception {
|
||||
String encoding = "UTF-8";
|
||||
if (requestUrl.contains("nlp")) {
|
||||
encoding = "GBK";
|
||||
}
|
||||
return HttpUtil.post(requestUrl, accessToken, contentType, params, encoding);
|
||||
}
|
||||
|
||||
public static String post(String requestUrl, String accessToken, String contentType, String params, String encoding)
|
||||
throws Exception {
|
||||
String url = requestUrl + "?access_token=" + accessToken;
|
||||
return HttpUtil.postGeneralUrl(url, contentType, params, encoding);
|
||||
}
|
||||
|
||||
public static String postGeneralUrl(String generalUrl, String contentType, String params, String encoding)
|
||||
throws Exception {
|
||||
URL url = new URL(generalUrl);
|
||||
// 打开和URL之间的连接
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
// 设置通用的请求属性
|
||||
connection.setRequestProperty("Content-Type", contentType);
|
||||
connection.setRequestProperty("Connection", "Keep-Alive");
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
|
||||
// 得到请求的输出流对象
|
||||
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
|
||||
out.write(params.getBytes(encoding));
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
// 建立实际的连接
|
||||
connection.connect();
|
||||
// 获取所有响应头字段
|
||||
Map<String, List<String>> headers = connection.getHeaderFields();
|
||||
// 遍历所有的响应头字段
|
||||
for (String key : headers.keySet()) {
|
||||
System.err.println(key + "--->" + headers.get(key));
|
||||
}
|
||||
// 定义 BufferedReader输入流来读取URL的响应
|
||||
BufferedReader in = null;
|
||||
in = new BufferedReader(
|
||||
new InputStreamReader(connection.getInputStream(), encoding));
|
||||
String result = "";
|
||||
String getLine;
|
||||
while ((getLine = in.readLine()) != null) {
|
||||
result += getLine;
|
||||
}
|
||||
in.close();
|
||||
System.err.println("result:" + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.imgrecognition.bauduai;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
public class Ingredient {
|
||||
private static final String requestUrl = "https://aip.baidubce.com/rest/2.0/image-classify/v1/classify/ingredient";
|
||||
private static final String accessToken = "24.f92314cba46ffeee34854093fa71966c.2592000.1700631460.282335-38996773";
|
||||
|
||||
public static String ingredient(String path) throws Exception {
|
||||
try {
|
||||
byte[] imgData = FileUtil.readFileByBytes(path);
|
||||
String imgStr = Base64Util.encode(imgData);
|
||||
String imgParam = URLEncoder.encode(imgStr, "UTF-8");
|
||||
String param = "image=" + imgParam;
|
||||
String result = HttpUtil.post(requestUrl, accessToken, param);
|
||||
Log.d("ingredient", "ingredient: " + result);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "can not get result";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,151 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.imgrecognition.camerax
|
||||
|
||||
import android.os.Build
|
||||
import android.Manifest
|
||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import com.google.accompanist.permissions.shouldShowRationale
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class PhotoComponent {
|
||||
|
||||
private var openGalleryLauncher: ManagedActivityResultLauncher<Unit?, PictureResult>? = null
|
||||
private var takePhotoLauncher: ManagedActivityResultLauncher<Unit?, PictureResult>? = null
|
||||
|
||||
private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
companion object {
|
||||
val instance get() = Helper.obj
|
||||
}
|
||||
|
||||
private object Helper {
|
||||
val obj = PhotoComponent()
|
||||
}
|
||||
|
||||
//监听拍照权限flow
|
||||
private val checkCameraPermission =
|
||||
MutableSharedFlow<Boolean?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
|
||||
private fun setCheckCameraPermissionState(value: Boolean?) {
|
||||
scope.launch {
|
||||
checkCameraPermission.emit(value)
|
||||
}
|
||||
}
|
||||
|
||||
//相册权限flow
|
||||
private val checkGalleryImagePermission =
|
||||
MutableSharedFlow<Boolean?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
|
||||
private fun setCheckGalleryPermissionState(value: Boolean?) {
|
||||
scope.launch {
|
||||
checkGalleryImagePermission.emit(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param galleryCallback 相册结果回调
|
||||
* @param graphCallback 拍照结果回调
|
||||
* @param permissionRationale 权限拒绝状态回调
|
||||
**/
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun Register(
|
||||
galleryCallback: (selectResult: PictureResult) -> Unit,
|
||||
graphCallback: (graphResult: PictureResult) -> Unit,
|
||||
permissionRationale: ((gallery: Boolean) -> Unit)? = null,
|
||||
) {
|
||||
val rememberGraphCallback = rememberUpdatedState(newValue = graphCallback)
|
||||
val rememberGalleryCallback = rememberUpdatedState(newValue = galleryCallback)
|
||||
openGalleryLauncher = rememberLauncherForActivityResult(contract = SelectPicture()) {
|
||||
rememberGalleryCallback.value.invoke(it)
|
||||
}
|
||||
takePhotoLauncher = rememberLauncherForActivityResult(contract = TakePhoto.instance) {
|
||||
rememberGraphCallback.value.invoke(it)
|
||||
}
|
||||
val readGalleryPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
//13以上的权限申请
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
var permissionCameraState by rememberSaveable { mutableStateOf(false) }
|
||||
var permissionGalleryState by rememberSaveable { mutableStateOf(false) }
|
||||
val permissionList = arrayListOf(
|
||||
Manifest.permission.CAMERA,
|
||||
readGalleryPermission,
|
||||
)
|
||||
val galleryPermissionState = rememberPermissionState(readGalleryPermission)
|
||||
val cameraPermissionState = rememberMultiplePermissionsState(permissionList)
|
||||
LaunchedEffect(Unit) {
|
||||
checkCameraPermission.collectLatest {
|
||||
permissionCameraState = it == true
|
||||
if (it == true) {
|
||||
if (cameraPermissionState.allPermissionsGranted) {
|
||||
setCheckCameraPermissionState(null)
|
||||
takePhotoLauncher?.launch(null)
|
||||
} else if (cameraPermissionState.shouldShowRationale) {
|
||||
setCheckCameraPermissionState(null)
|
||||
permissionRationale?.invoke(false)
|
||||
} else {
|
||||
cameraPermissionState.launchMultiplePermissionRequest()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
checkGalleryImagePermission.collectLatest {
|
||||
permissionGalleryState = it == true
|
||||
if (it == true) {
|
||||
if (galleryPermissionState.status.isGranted) {
|
||||
setCheckGalleryPermissionState(null)
|
||||
openGalleryLauncher?.launch(null)
|
||||
} else if (galleryPermissionState.status.shouldShowRationale) {
|
||||
setCheckGalleryPermissionState(null)
|
||||
permissionRationale?.invoke(true)
|
||||
} else {
|
||||
galleryPermissionState.launchPermissionRequest()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LaunchedEffect(cameraPermissionState.allPermissionsGranted) {
|
||||
if (cameraPermissionState.allPermissionsGranted && permissionCameraState) {
|
||||
setCheckCameraPermissionState(null)
|
||||
takePhotoLauncher?.launch(null)
|
||||
}
|
||||
}
|
||||
LaunchedEffect(galleryPermissionState.status.isGranted) {
|
||||
if (galleryPermissionState.status.isGranted && permissionGalleryState) {
|
||||
setCheckGalleryPermissionState(null)
|
||||
openGalleryLauncher?.launch(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//调用选择图片功能
|
||||
fun selectImage() {
|
||||
setCheckGalleryPermissionState(true)
|
||||
}
|
||||
//调用拍照
|
||||
fun takePhoto() {
|
||||
setCheckCameraPermissionState(true)
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.imgrecognition.camerax
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
|
||||
class SelectPicture : ActivityResultContract<Unit?, PictureResult>() {
|
||||
|
||||
private var context: Context? = null
|
||||
|
||||
override fun createIntent(context: Context, input: Unit?): Intent {
|
||||
this.context = context
|
||||
return Intent(Intent.ACTION_PICK).setType("image/*")
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): PictureResult {
|
||||
return PictureResult(intent?.data, resultCode == Activity.RESULT_OK)
|
||||
}
|
||||
}
|
||||
//图片结果
|
||||
class PictureResult(val uri: Uri?, val isSuccess: Boolean)
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.imgrecognition.path;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class Path {
|
||||
public static String getPath(Context context, Uri uri) {
|
||||
String path = null;
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
if (cursor.moveToFirst()) {
|
||||
try {
|
||||
path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@ -1,218 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.login
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountBox
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.fruitandvegetableguide.R
|
||||
import com.example.fruitandvegetableguide.utils.loginVerification
|
||||
|
||||
@Composable
|
||||
fun LoginScreen(
|
||||
onClickToRegister: () -> Unit = {},
|
||||
onClickToMain: (userid: Int) -> Unit = {}
|
||||
) {
|
||||
var userid by remember { mutableIntStateOf(-1) }
|
||||
var username by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
val pwdVisualTransformation = PasswordVisualTransformation()
|
||||
var showPwd by remember { mutableStateOf(true) }
|
||||
val transformation = if (showPwd) pwdVisualTransformation else VisualTransformation.None
|
||||
val context = LocalContext.current
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
TextButton(onClick = onClickToRegister) {
|
||||
Text(
|
||||
text = "注册",
|
||||
fontSize = 20.sp,
|
||||
textAlign = TextAlign.End,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(20.dp)
|
||||
)
|
||||
}
|
||||
Column {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(3f)
|
||||
.background(Color.White)
|
||||
.padding(40.dp)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Column {
|
||||
TextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = username,
|
||||
onValueChange = { str -> username = str },
|
||||
placeholder = {
|
||||
Text("账号")
|
||||
},
|
||||
colors = TextFieldDefaults.colors(focusedTextColor = Color.Black),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.AccountBox,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
)
|
||||
TextField(
|
||||
value = password,
|
||||
onValueChange = { str -> password = str },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
placeholder = {
|
||||
Text("密码")
|
||||
},
|
||||
visualTransformation = transformation,
|
||||
colors = TextFieldDefaults.colors(focusedTextColor = Color.Black),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Lock,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (showPwd) {
|
||||
IconButton(onClick = { showPwd = !showPwd }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.sleep),
|
||||
contentDescription = null,
|
||||
Modifier.size(30.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = { showPwd = !showPwd }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.eye),
|
||||
contentDescription = null,
|
||||
Modifier.size(30.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = "快捷登录", fontSize = 16.sp, color = Color.Gray)
|
||||
Text(text = "忘记密码", fontSize = 16.sp, color = Color.Gray)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
userid = loginVerification(username, password)
|
||||
if (username != "" && password != "" && userid != -1) {
|
||||
Toast.makeText(context, "登陆成功", Toast.LENGTH_SHORT).show()
|
||||
onClickToMain(userid)
|
||||
} else {
|
||||
Toast.makeText(context, "登陆失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(
|
||||
0xff5c59fe
|
||||
)
|
||||
),
|
||||
contentPadding = PaddingValues(12.dp, 16.dp)
|
||||
) {
|
||||
Text("登录", color = Color.White, fontSize = 18.sp)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(100.dp))
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Row(
|
||||
Modifier
|
||||
.background(Color(0xFFCFC5C5))
|
||||
.padding(end = 10.dp)
|
||||
) {}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Text(text = "第三方登录", fontSize = 16.sp, color = Color.Gray)
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.Top
|
||||
) {
|
||||
repeat(3) {
|
||||
Column(
|
||||
Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.size(50.dp),
|
||||
painter = painterResource(id = R.drawable.qq),
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
"QQ",
|
||||
color = Color(0xffcdcdcd),
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun Login() {
|
||||
LoginScreen()
|
||||
}
|
||||
@ -1,359 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.paddingFromBaseline
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material.icons.filled.Camera
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.Spa
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.R
|
||||
import com.example.fruitandvegetableguide.ui.theme.FruitandVegetableGuideTheme
|
||||
import com.example.fruitandvegetableguide.utils.guideListInit
|
||||
import com.example.fruitandvegetableguide.utils.postListInit
|
||||
|
||||
//主页
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
userid: Int? = 1,
|
||||
onClickToSearch: (search: String) -> Unit = {},
|
||||
onClickToUser: (userid: Int) -> Unit = {},
|
||||
onClickToPhotograph: () -> Unit = {},
|
||||
onClickToGuide: () -> Unit = {},
|
||||
onClickToCommunity: (userid: Int) -> Unit = {},
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
) {
|
||||
FruitandVegetableGuideTheme {
|
||||
Scaffold(bottomBar = {
|
||||
MyBottomNavigation(
|
||||
userid = userid ?: 1,
|
||||
onClickToUser = onClickToUser,
|
||||
onClickToPhotograph = onClickToPhotograph
|
||||
)
|
||||
}) { padding ->
|
||||
HomeScreen(
|
||||
userid = userid ?: 1,
|
||||
modifier = Modifier.padding(padding),
|
||||
onClickToSearch = onClickToSearch,
|
||||
onClickToGuide = onClickToGuide,
|
||||
onClickToCommunity = onClickToCommunity,
|
||||
onClickToGuideDetail = onClickToGuideDetail,
|
||||
onClickToPostDetail = onClickToPostDetail
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//主屏幕
|
||||
@Composable
|
||||
fun HomeScreen(
|
||||
userid: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToSearch: (search: String) -> Unit,
|
||||
onClickToGuide: () -> Unit = {},
|
||||
onClickToCommunity: (userid: Int) -> Unit = {},
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
) {
|
||||
Column(modifier.verticalScroll(rememberScrollState())) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
SearchBar(
|
||||
Modifier.padding(horizontal = 16.dp),
|
||||
onClickToSearch = onClickToSearch
|
||||
)
|
||||
Column {
|
||||
TextButton(onClick = onClickToGuide) {
|
||||
Text(
|
||||
text = "指南",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier
|
||||
.paddingFromBaseline(top = 40.dp, bottom = 16.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
}
|
||||
GuideGrid(onClickToGuideDetail = onClickToGuideDetail)
|
||||
}
|
||||
|
||||
Column {
|
||||
TextButton(onClick = { onClickToCommunity(userid) }) {
|
||||
Text(
|
||||
text = "社区",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier
|
||||
.paddingFromBaseline(top = 40.dp, bottom = 16.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
}
|
||||
PostGrid(onClickToPostDetail = onClickToPostDetail)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
//搜索框
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToSearch: (search: String) -> Unit
|
||||
) {
|
||||
var search by remember {
|
||||
mutableStateOf("")
|
||||
}
|
||||
TextField(
|
||||
value = search, onValueChange = { str -> search = str },
|
||||
leadingIcon = {
|
||||
IconButton(onClick = {
|
||||
//路由不能传递空字符串
|
||||
if (search == "") {
|
||||
search = " "
|
||||
}
|
||||
onClickToSearch(search)
|
||||
}) {
|
||||
Icon(imageVector = Icons.Default.Search, contentDescription = null)
|
||||
}
|
||||
},
|
||||
colors = TextFieldDefaults.colors(
|
||||
unfocusedContainerColor = MaterialTheme.colorScheme.surface,
|
||||
focusedContainerColor = MaterialTheme.colorScheme.surface
|
||||
),
|
||||
placeholder = { Text(text = "搜索") },
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(56.dp)
|
||||
)
|
||||
}
|
||||
|
||||
//指南元素
|
||||
@Composable
|
||||
fun GuideElement(
|
||||
modifier: Modifier = Modifier,
|
||||
@DrawableRes drawable: Int,
|
||||
guideId: Int,
|
||||
kind: String,
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
) {
|
||||
Button(
|
||||
onClick = { onClickToGuideDetail(guideId) },
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.White,
|
||||
),
|
||||
contentPadding = PaddingValues(1.dp),
|
||||
modifier = Modifier.width(90.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = drawable),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = if (R.drawable.loading == drawable) {
|
||||
Modifier
|
||||
// .size(24.dp)
|
||||
// .padding(32.dp)
|
||||
.clip(CircleShape)
|
||||
} else {
|
||||
Modifier
|
||||
.size(88.dp)
|
||||
.clip(CircleShape)
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = kind,
|
||||
modifier = Modifier.paddingFromBaseline(top = 24.dp, bottom = 8.dp),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = Color.Black
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//帖子元素
|
||||
@SuppressLint("InvalidColorHexValue")
|
||||
@Composable
|
||||
fun PostCard(
|
||||
postId: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
@DrawableRes drawable: Int,
|
||||
title: String,
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
) {
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
modifier = modifier,
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.width(255.dp)
|
||||
) {
|
||||
Button(
|
||||
onClick = { onClickToPostDetail(postId) },
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0x0000),
|
||||
),
|
||||
modifier = Modifier.width(251.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = drawable),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = if (R.drawable.loading != drawable) {
|
||||
Modifier.size(80.dp)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = Color.Black,
|
||||
modifier = Modifier.padding(horizontal = 10.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//指南的网格显示
|
||||
@Preview
|
||||
@Composable
|
||||
fun GuideGrid(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
) {
|
||||
val guideList = guideListInit()
|
||||
LazyHorizontalGrid(
|
||||
rows = GridCells.Fixed(2),
|
||||
contentPadding = PaddingValues(horizontal = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
modifier = modifier.height(300.dp)
|
||||
) {
|
||||
items(guideList) { item ->
|
||||
GuideElement(
|
||||
guideId = item.id,
|
||||
drawable = item.imgId,
|
||||
kind = item.kind,
|
||||
onClickToGuideDetail = onClickToGuideDetail
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//帖子的网格显示
|
||||
@Composable
|
||||
fun PostGrid(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
) {
|
||||
val postList = postListInit()
|
||||
LazyHorizontalGrid(
|
||||
rows = GridCells.Fixed(4),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
modifier = modifier.height(300.dp)
|
||||
) {
|
||||
items(postList) { item ->
|
||||
PostCard(
|
||||
postId = item.id,
|
||||
drawable = item.imgId,
|
||||
title = item.title,
|
||||
onClickToPostDetail = onClickToPostDetail
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//底部导航栏
|
||||
@Composable
|
||||
fun MyBottomNavigation(
|
||||
userid: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToUser: (userid: Int) -> Unit = {},
|
||||
onClickToPhotograph: () -> Unit = {},
|
||||
) {
|
||||
NavigationBar(containerColor = MaterialTheme.colorScheme.surfaceVariant, modifier = modifier) {
|
||||
NavigationBarItem(icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Spa,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
label = { Text(text = "首页") },
|
||||
selected = true,
|
||||
onClick = { })
|
||||
NavigationBarItem(
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Camera,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
label = { Text(text = "识别") },
|
||||
selected = false,
|
||||
onClick = onClickToPhotograph
|
||||
)
|
||||
NavigationBarItem(icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.AccountCircle,
|
||||
contentDescription = null
|
||||
)
|
||||
}, label = { Text(text = "用户") },
|
||||
selected = false,
|
||||
onClick = { onClickToUser(userid) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,205 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.register
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountBox
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.fruitandvegetableguide.R
|
||||
import com.example.fruitandvegetableguide.utils.register
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun RegisterScreen(onClickBack: () -> Unit = {}) {
|
||||
var username by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var rePassword by remember { mutableStateOf("") }
|
||||
val pwdVisualTransformation = PasswordVisualTransformation()
|
||||
var showPwd by remember { mutableStateOf(true) }
|
||||
val transformation = if (showPwd) pwdVisualTransformation else VisualTransformation.None
|
||||
val context = LocalContext.current
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = "注册",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
})
|
||||
Column() {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(3f)
|
||||
.background(Color.White)
|
||||
.padding(40.dp)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Column {
|
||||
TextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = username,
|
||||
onValueChange = { str -> username = str },
|
||||
placeholder = {
|
||||
Text("账号")
|
||||
},
|
||||
colors = TextFieldDefaults.colors(focusedTextColor = Color.Black),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.AccountBox,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
)
|
||||
TextField(
|
||||
value = password,
|
||||
onValueChange = { str -> password = str },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
placeholder = {
|
||||
Text("密码")
|
||||
},
|
||||
visualTransformation = transformation,
|
||||
colors = TextFieldDefaults.colors(focusedTextColor = Color.Black),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Lock,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (showPwd) {
|
||||
IconButton(onClick = { showPwd = !showPwd }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.sleep),
|
||||
contentDescription = null,
|
||||
Modifier.size(30.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = { showPwd = !showPwd }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.eye),
|
||||
contentDescription = null,
|
||||
Modifier.size(30.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
TextField(
|
||||
value = rePassword,
|
||||
onValueChange = { str -> rePassword = str },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
placeholder = {
|
||||
Text("再次输入密码")
|
||||
},
|
||||
visualTransformation = transformation,
|
||||
colors = TextFieldDefaults.colors(focusedTextColor = Color.Black),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Lock,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (showPwd) {
|
||||
IconButton(onClick = { showPwd = !showPwd }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.sleep),
|
||||
contentDescription = null,
|
||||
Modifier.size(30.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = { showPwd = !showPwd }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.eye),
|
||||
contentDescription = null,
|
||||
Modifier.size(30.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
if (username != "" && password != "" && password == rePassword && register(
|
||||
username,
|
||||
password
|
||||
)
|
||||
) {
|
||||
Toast.makeText(context, "注册成功", Toast.LENGTH_SHORT).show()
|
||||
onClickBack()
|
||||
} else {
|
||||
Toast.makeText(context, "注册失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(
|
||||
0xff5c59fe
|
||||
)
|
||||
),
|
||||
contentPadding = PaddingValues(12.dp, 16.dp)
|
||||
) {
|
||||
Text("注册", color = Color.White, fontSize = 18.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(120.dp))
|
||||
}
|
||||
}
|
||||
@ -1,325 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.search
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.ArrowForwardIos
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.data.Guide
|
||||
import com.example.fruitandvegetableguide.data.Post
|
||||
import com.example.fruitandvegetableguide.utils.getGuideByKind
|
||||
import com.example.fruitandvegetableguide.utils.getPostByLabels
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun SearchScreen(
|
||||
search: String? = "",
|
||||
onClickBack: () -> Unit = {},
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {}
|
||||
) {
|
||||
var thisSearch by rememberSaveable {
|
||||
mutableStateOf(search)
|
||||
}
|
||||
var guideClassify by remember {
|
||||
mutableStateOf(true)
|
||||
} //筛选指南
|
||||
var postClassify by remember {
|
||||
mutableStateOf(false)
|
||||
} //筛选帖子
|
||||
|
||||
//刷新,当再次点击搜索的时候,该值改变,触发刷新
|
||||
var refresh by remember {
|
||||
mutableIntStateOf(1)
|
||||
}
|
||||
val guides = getGuideByKind(thisSearch ?: "") //搜索指南
|
||||
val posts = getPostByLabels(thisSearch ?: "") //搜索帖子
|
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = "搜索",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
})
|
||||
//搜索框
|
||||
TextField(
|
||||
value = thisSearch ?: "", onValueChange = { str -> thisSearch = str },
|
||||
leadingIcon = {
|
||||
IconButton(onClick = { refresh += 1 }) {
|
||||
Icon(imageVector = Icons.Default.Search, contentDescription = null)
|
||||
}
|
||||
},
|
||||
colors = TextFieldDefaults.colors(
|
||||
unfocusedContainerColor = MaterialTheme.colorScheme.surface,
|
||||
focusedContainerColor = MaterialTheme.colorScheme.surface
|
||||
),
|
||||
placeholder = { Text(text = "搜索") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(56.dp)
|
||||
)
|
||||
|
||||
//筛选按钮
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Spacer(modifier = Modifier.requiredWidth(15.dp))
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
postClassify = !postClassify
|
||||
guideClassify = !guideClassify
|
||||
},
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
contentPadding = PaddingValues(horizontal = 30.dp, vertical = 16.dp),
|
||||
modifier = Modifier.bounceClick(),
|
||||
enabled = postClassify && !guideClassify
|
||||
) {
|
||||
Text(text = "筛选指南")
|
||||
}
|
||||
}
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
guideClassify = !guideClassify
|
||||
postClassify = !postClassify
|
||||
},
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
contentPadding = PaddingValues(horizontal = 30.dp, vertical = 16.dp),
|
||||
modifier = Modifier.bounceClick(),
|
||||
enabled = guideClassify && !postClassify //不可用
|
||||
) {
|
||||
Text(text = "筛选帖子")
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.requiredWidth(15.dp))
|
||||
}
|
||||
|
||||
//显示结果列表
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
if (guideClassify) {
|
||||
Guides(guidesList = guides, onClickToGuideDetail = onClickToGuideDetail)
|
||||
}
|
||||
if (postClassify) {
|
||||
Posts(postsList = posts, onClickToPostDetail = onClickToPostDetail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//帖子列表的显示
|
||||
@Composable
|
||||
fun Posts(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
postsList: List<Post>
|
||||
) {
|
||||
LazyColumn(modifier = modifier.padding(vertical = 4.dp)) {
|
||||
items(items = postsList) { post ->
|
||||
Post(
|
||||
post = post,
|
||||
onClickToPostDetail = onClickToPostDetail
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//单个帖子的显示
|
||||
@Composable
|
||||
fun Post(
|
||||
post: Post,
|
||||
onClickToPostDetail: (postId: Int) -> Unit = {},
|
||||
) {
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary),
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioMediumBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Text(
|
||||
text = post.title,
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(text = post.labels)
|
||||
}
|
||||
Button(onClick = {
|
||||
onClickToPostDetail(post.id)
|
||||
}) {
|
||||
Icon(imageVector = Icons.Filled.ArrowForwardIos, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//指南列表的显示
|
||||
@Composable
|
||||
fun Guides(
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
guidesList: List<Guide>
|
||||
) {
|
||||
LazyColumn(modifier = modifier.padding(vertical = 4.dp)) {
|
||||
items(items = guidesList) { guide ->
|
||||
Guide(
|
||||
guide = guide,
|
||||
onClickToGuideDetail = onClickToGuideDetail
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//单个指南的显示
|
||||
@Composable
|
||||
fun Guide(
|
||||
guide: Guide,
|
||||
onClickToGuideDetail: (guideId: Int) -> Unit = {},
|
||||
) {
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary),
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioMediumBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Text(
|
||||
text = guide.kind,
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(text = guide.suitable)
|
||||
}
|
||||
Button(onClick = {
|
||||
onClickToGuideDetail(guide.id)
|
||||
}) {
|
||||
Icon(imageVector = Icons.Filled.ArrowForwardIos, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//实现按钮点击效果
|
||||
enum class ButtonState { Pressed, Idle }
|
||||
|
||||
fun Modifier.bounceClick() = composed {
|
||||
var buttonState by remember { mutableStateOf(ButtonState.Idle) }
|
||||
val scale by animateFloatAsState(if (buttonState == ButtonState.Pressed) 0.70f else 1f)
|
||||
|
||||
this
|
||||
.graphicsLayer {
|
||||
scaleX = scale
|
||||
scaleY = scale
|
||||
}
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = { }
|
||||
)
|
||||
.pointerInput(buttonState) {
|
||||
awaitPointerEventScope {
|
||||
buttonState = if (buttonState == ButtonState.Pressed) {
|
||||
waitForUpOrCancellation()
|
||||
ButtonState.Idle
|
||||
} else {
|
||||
awaitFirstDown(false)
|
||||
ButtonState.Pressed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
||||
@ -1,70 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun FruitandVegetableGuideTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
window.statusBarColor = colorScheme.primary.toArgb()
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
||||
@ -1,16 +0,0 @@
|
||||
package com.example.fruitandvegetableguide.ui.user
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
|
||||
|
||||
//一个类,用来方便显示我的帖子
|
||||
class MyPost(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val content: String,
|
||||
initialChecked: Boolean = false
|
||||
) {
|
||||
var checked: Boolean by mutableStateOf(initialChecked)
|
||||
}
|
||||
@ -1,194 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.user
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.data.Post
|
||||
import com.example.fruitandvegetableguide.utils.DeletePost
|
||||
import com.example.fruitandvegetableguide.utils.getPostByPostId
|
||||
import com.example.fruitandvegetableguide.utils.getPostByUserid
|
||||
|
||||
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
|
||||
@Composable
|
||||
fun MyPostScreen(userid: Int? = 1, onClickBack: () -> Unit = {}) {
|
||||
val context = LocalContext.current
|
||||
// 如果执行了删除操作,需要刷新页面
|
||||
val deleteFlag1 by remember {
|
||||
mutableIntStateOf(0)
|
||||
}
|
||||
var deleteFlag2 by remember {
|
||||
mutableIntStateOf(0)
|
||||
}
|
||||
|
||||
var myPosts = getPostByUserid(userid ?: 1)
|
||||
|
||||
/*var id1 = ""
|
||||
for (myPost in myPosts) {
|
||||
id1 += myPost.id
|
||||
}
|
||||
Log.d("MyPostScreen", "MyPostScreen1111,the one myPost: \n${id1}")*/
|
||||
|
||||
//新建一个列表用于显示
|
||||
var postList = transMyPostList(myPosts)
|
||||
|
||||
/*var id2 = ""
|
||||
for (post in postList) {
|
||||
id2 += post.id
|
||||
}
|
||||
Log.d("MyPostScreen", "MyPostScreen22222,the two postList: \n${id2}")*/
|
||||
|
||||
//记录选中的帖子
|
||||
var postSelected = mutableListOf<Post>().toMutableStateList()
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = "我的帖子",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onClickBack) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = {
|
||||
if (DeletePost(postSelected)) {
|
||||
postSelected = mutableListOf<Post>().toMutableStateList() //删除后,清空选中的帖子列表
|
||||
Toast.makeText(context, "删除成功", Toast.LENGTH_SHORT).show()
|
||||
deleteFlag2 += 1
|
||||
} else {
|
||||
Toast.makeText(context, "删除失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}) {
|
||||
Icon(imageVector = Icons.Default.Delete, contentDescription = null)
|
||||
}
|
||||
})
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
|
||||
if (postList.isEmpty()) {
|
||||
Text(
|
||||
text = "您还没分享过经验",
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
} else {
|
||||
if (deleteFlag1 < deleteFlag2) {
|
||||
myPosts = getPostByUserid(userid ?: 1)
|
||||
postList = transMyPostList(myPosts)
|
||||
deleteFlag2 = 0
|
||||
}
|
||||
/*var id3 = ""
|
||||
for (myPost in myPosts) {
|
||||
id3 += myPost.id
|
||||
}
|
||||
Log.d("MyPostScreen", "MyPostScreen22222 the three: \n${id3}")
|
||||
var id4 = ""
|
||||
for (post in postList) {
|
||||
id4 += post.id
|
||||
}
|
||||
Log.d("MyPostScreen", "MyPostScreen22222,the four postList: \n${id4}")*/
|
||||
|
||||
LazyColumn {
|
||||
items(items = postList) { post ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier
|
||||
.border(1.dp, Color.Black, RoundedCornerShape(8.dp))
|
||||
.padding(8.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp),
|
||||
text = post.title,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp),
|
||||
text = post.content
|
||||
)
|
||||
}
|
||||
Checkbox(
|
||||
checked = post.checked,
|
||||
onCheckedChange = { checked ->
|
||||
if (post.checked) {
|
||||
postSelected.remove(getPostByPostId(post.id))
|
||||
} else {
|
||||
postSelected.add(getPostByPostId(post.id))
|
||||
}
|
||||
post.checked = checked
|
||||
})
|
||||
}
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//转换列表,方便删除选择和删除
|
||||
private fun transMyPostList(myPosts: List<Post>): List<MyPost> {
|
||||
var newMyPosts = mutableListOf<MyPost>()
|
||||
for (myPost in myPosts) {
|
||||
newMyPosts.add(
|
||||
MyPost(
|
||||
myPost.id,
|
||||
myPost.title,
|
||||
if (myPost.content.length > 15) {
|
||||
myPost.content.substring(0, 15) + "……"
|
||||
} else {
|
||||
myPost.content + "……"
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
return newMyPosts
|
||||
}
|
||||
@ -1,149 +0,0 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package com.example.fruitandvegetableguide.ui.user
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material.icons.filled.Camera
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.Password
|
||||
import androidx.compose.material.icons.filled.Spa
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.fruitandvegetableguide.R
|
||||
import com.example.fruitandvegetableguide.utils.getUsernameByUserid
|
||||
|
||||
@Composable
|
||||
fun UserScreen(
|
||||
userid: Int? = 1,
|
||||
onClickToMain: () -> Unit = {},
|
||||
onClickToMyPost: (userid: Int) -> Unit = {},
|
||||
onClickToPhotograph: () -> Unit = {},
|
||||
) {
|
||||
val username: String = getUsernameByUserid(userid ?: 1)
|
||||
Scaffold(bottomBar = {
|
||||
MyBottomNavigation(
|
||||
userid = userid ?: 1,
|
||||
onClickToMain = onClickToMain,
|
||||
onClickToPhotograph = onClickToPhotograph
|
||||
)
|
||||
}) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text = "用户",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
)
|
||||
})
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Row {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.user_circle),
|
||||
contentDescription = null,
|
||||
Modifier.padding(16.dp)
|
||||
)
|
||||
Column {
|
||||
Text(
|
||||
text = "用户",
|
||||
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.ExtraBold)
|
||||
)
|
||||
Text(text = "账号:$username")
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Row {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Edit,
|
||||
contentDescription = null,
|
||||
Modifier.padding(16.dp)
|
||||
)
|
||||
OutlinedButton(onClick = { onClickToMyPost(userid ?: 1) }) {
|
||||
Text(text = "我的帖子")
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.requiredHeight(10.dp))
|
||||
Row {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Password,
|
||||
contentDescription = null,
|
||||
Modifier.padding(16.dp)
|
||||
)
|
||||
OutlinedButton(onClick = { /*TODO*/ }) {
|
||||
Text(text = "修改密码")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//底部导航栏
|
||||
@Composable
|
||||
fun MyBottomNavigation(
|
||||
userid: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
onClickToMain: () -> Unit = {},
|
||||
onClickToPhotograph: () -> Unit = {},
|
||||
) {
|
||||
NavigationBar(containerColor = MaterialTheme.colorScheme.surfaceVariant, modifier = modifier) {
|
||||
NavigationBarItem(
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Spa,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
label = { Text(text = "首页") },
|
||||
selected = false,
|
||||
onClick = onClickToMain
|
||||
)
|
||||
NavigationBarItem(
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Camera,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
label = { Text(text = "识别") },
|
||||
selected = false,
|
||||
onClick = onClickToPhotograph
|
||||
)
|
||||
NavigationBarItem(icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.AccountCircle,
|
||||
contentDescription = null
|
||||
)
|
||||
}, label = { Text(text = "用户") },
|
||||
selected = true,
|
||||
onClick = { })
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 86 KiB |
@ -1,170 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="32"
|
||||
android:viewportHeight="32">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16,5.887C22.086,5.887 22.395,11.324 22.73,12.395C22.73,12.395 23.211,12.93 23.324,13.746C23.398,14.273 23.098,14.871 23.098,14.871C23.098,14.871 25.043,17.492 25.043,19.551C25.043,20.836 24.664,21.5 24.223,21.5C23.777,21.5 23.129,20.141 23.129,20.141C23.129,20.141 22.113,22.309 21.605,22.621C21.098,22.93 23.438,23.27 23.438,24.281C23.438,25.297 21.578,25.746 20.059,25.746C18.535,25.746 16.113,24.957 16.113,24.957L15.238,24.93C15.238,24.93 14.563,25.887 11.773,25.887C8.984,25.887 7.773,25.129 7.773,24.227C7.773,23.012 9.551,22.848 9.551,22.848C9.551,22.848 8.418,22.531 7.461,19.852C7.461,19.852 6.797,21.297 5.859,21.297C5.859,21.297 5.465,21.063 5.465,19.746C5.465,17.023 7.422,15.695 8.266,14.879C8.266,14.879 8.125,14.523 8.199,14.082C8.281,13.59 8.574,13.293 8.574,13.293C8.574,13.293 8.465,12.703 8.875,12.227C8.957,10.902 9.914,5.887 16,5.887M16,3.887C9.602,3.887 7.332,8.477 6.93,11.555C6.738,11.93 6.629,12.316 6.586,12.68C6.434,12.969 6.297,13.324 6.227,13.746C6.207,13.852 6.195,13.961 6.188,14.063C5.078,15.082 3.465,16.82 3.465,19.746C3.465,21.777 4.211,22.645 4.84,23.016L5.309,23.297L5.859,23.297C5.875,23.297 5.891,23.297 5.91,23.297C5.82,23.582 5.773,23.891 5.773,24.227C5.773,25.086 6.207,27.891 11.773,27.891C13.813,27.891 15.086,27.449 15.867,26.977C16.688,27.223 18.605,27.746 20.055,27.746C23.324,27.746 25.438,26.387 25.438,24.281C25.438,23.906 25.363,23.574 25.242,23.277C26.207,22.84 27.039,21.711 27.039,19.551C27.039,17.656 25.992,15.668 25.281,14.535C25.336,14.211 25.355,13.848 25.305,13.473C25.188,12.633 24.852,11.965 24.582,11.547C24.574,11.508 24.566,11.469 24.559,11.43C23.512,6.422 20.629,3.887 16,3.887Z"/>
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 811 KiB |
@ -1,24 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,15c-4.132,0 -7.98,-1.214 -10.294,-3.249a1,1 0,1 1,1.32 -1.502C4.986,11.972 8.34,13 12,13s7.014,-1.028 8.974,-2.751a1,1 0,1 1,1.32 1.502C19.98,13.786 16.132,15 12,15Z"
|
||||
android:fillColor="#333"/>
|
||||
<path
|
||||
android:pathData="M12,18a1,1 0,0 1,-1 -1V14a1,1 0,0 1,2 0v3A1,1 0,0 1,12 18Z"
|
||||
android:fillColor="#333"/>
|
||||
<path
|
||||
android:pathData="M7.749,17.667a0.964,0.964 0,0 1,-0.17 -0.015A0.999,0.999 0,0 1,6.762 16.498L7.267,13.563a1,1 0,1 1,1.971 0.339l-0.505,2.935A1,1 0,0 1,7.749 17.667Z"
|
||||
android:fillColor="#333"/>
|
||||
<path
|
||||
android:pathData="M3.636,16.306a1.001,1.001 0,0 1,-0.942 -1.336l0.979,-2.745a1,1 0,1 1,1.884 0.672L4.578,15.642A1.001,1.001 0,0 1,3.636 16.306Z"
|
||||
android:fillColor="#333"/>
|
||||
<path
|
||||
android:pathData="M16.251,17.667a1,1 0,0 1,-0.984 -0.831l-0.505,-2.935a1,1 0,0 1,1.971 -0.339l0.505,2.935a0.999,0.999 0,0 1,-0.816 1.155A0.964,0.964 0,0 1,16.251 17.667Z"
|
||||
android:fillColor="#333"/>
|
||||
<path
|
||||
android:pathData="M20.364,16.306a1,1 0,0 1,-0.942 -0.665L18.444,12.897a1,1 0,1 1,1.884 -0.672l0.979,2.745a1.001,1.001 0,0 1,-0.942 1.336Z"
|
||||
android:fillColor="#333"/>
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 3.4 MiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 109 KiB |
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 982 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
||||
@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<string name="app_name">FruitandVegetableGuide</string>
|
||||
</resources>
|
||||