mirror of
https://github.com/f-droid/fdroidclient.git
synced 2026-05-06 14:42:58 -04:00
[app] New AddRepoActivity in compose
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
// add -Pstrict.release to the gradle command line to enable
|
||||
if (project.hasProperty('strict.release')) {
|
||||
@@ -100,6 +101,14 @@ android {
|
||||
cruncherEnabled = false
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.4.6"
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
@@ -164,6 +173,7 @@ dependencies {
|
||||
|
||||
implementation 'com.google.android.material:material:1.9.0'
|
||||
|
||||
implementation('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false }
|
||||
implementation 'com.google.zxing:core:3.3.3' // newer version need minSdk 24 or library desugering
|
||||
implementation 'info.guardianproject.netcipher:netcipher:2.2.0-alpha'
|
||||
//noinspection GradleDependency -> Commons IO > 2.5 uses java.nio.file, which requires desugaring
|
||||
@@ -178,6 +188,7 @@ dependencies {
|
||||
implementation 'io.reactivex.rxjava3:rxjava:3.0.9'
|
||||
|
||||
implementation "com.github.bumptech.glide:glide:4.14.2"
|
||||
implementation "com.github.bumptech.glide:compose:1.0.0-alpha.1"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:4.14.2"
|
||||
|
||||
implementation 'org.bouncycastle:bcprov-jdk15to18:1.71'
|
||||
@@ -186,6 +197,15 @@ dependencies {
|
||||
fullImplementation 'org.jmdns:jmdns:3.5.5'
|
||||
fullImplementation 'org.nanohttpd:nanohttpd:2.3.1'
|
||||
|
||||
implementation platform('androidx.compose:compose-bom:2023.06.01')
|
||||
implementation 'androidx.compose.material:material'
|
||||
implementation 'androidx.compose.material:material-icons-extended'
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose"
|
||||
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||
implementation 'androidx.activity:activity-compose:1.7.2'
|
||||
implementation "com.google.accompanist:accompanist-themeadapter-material:0.30.1"
|
||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||
|
||||
testImplementation 'androidx.test:core:1.4.0'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.robolectric:robolectric:4.8.1'
|
||||
@@ -196,7 +216,7 @@ dependencies {
|
||||
androidTestImplementation 'androidx.test:core:1.4.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.4.0'
|
||||
androidTestImplementation 'androidx.test:monitor:1.5.0'
|
||||
androidTestImplementation 'androidx.test:monitor:1.4.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
android:allowBackup="true"
|
||||
android:description="@string/app_description"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="${applicationLabel}"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
@@ -91,6 +92,16 @@
|
||||
android:launchMode="singleTask"
|
||||
android:parentActivityName=".views.main.MainActivity"></activity>
|
||||
|
||||
<activity
|
||||
android:name=".views.repos.AddRepoActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:parentActivityName=".views.main.MainActivity" />
|
||||
|
||||
<activity
|
||||
android:name="com.journeyapps.barcodescanner.CaptureActivity"
|
||||
android:screenOrientation="fullSensor"
|
||||
tools:replace="screenOrientation" />
|
||||
|
||||
<activity
|
||||
android:name=".NfcNotEnabledActivity"
|
||||
android:configChanges="layoutDirection|locale"
|
||||
|
||||
@@ -1,441 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.integration.android;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>A utility class which helps ease integration with Barcode Scanner via {@link Intent}s. This is a simple
|
||||
* way to invoke barcode scanning and receive the result, without any need to integrate, modify, or learn the
|
||||
* project's source code.</p>
|
||||
*
|
||||
* <h2>Initiating a barcode scan</h2>
|
||||
*
|
||||
* <p>To integrate, create an instance of {@code IntentIntegrator} and call {@link #initiateScan()} and wait
|
||||
* for the result in your app.</p>
|
||||
*
|
||||
* <p>It does require that the Barcode Scanner (or work-alike) application is installed. The
|
||||
* {@link #initiateScan()} method will prompt the user to download the application, if needed.</p>
|
||||
*
|
||||
* <p>There are a few steps to using this integration. First, your {@link AppCompatActivity} must implement
|
||||
* the method {@link AppCompatActivity#onActivityResult(int, int, Intent)} and include a line of code like this:</p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
* IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
|
||||
* if (scanResult != null) {
|
||||
* // handle scan result
|
||||
* }
|
||||
* // else continue with any other code you need in the method
|
||||
* ...
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>This is where you will handle a scan result.</p>
|
||||
*
|
||||
* <p>Second, just call this in response to a user action somewhere to begin the scan process:</p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* IntentIntegrator integrator = new IntentIntegrator(yourActivity);
|
||||
* integrator.initiateScan();
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Note that {@link #initiateScan()} returns an {@link AlertDialog} which is non-null if the
|
||||
* user was prompted to download the application. This lets the calling app potentially manage the dialog.
|
||||
* In particular, ideally, the app dismisses the dialog if it's still active in its
|
||||
* {@link AppCompatActivity#onPause()}
|
||||
* method.</p>
|
||||
*
|
||||
* <p>You can use {@link #setTitle(String)} to customize the title of this download prompt dialog (or, use
|
||||
* {@link #setTitleByID(int)} to set the title by string resource ID.) Likewise, the prompt message, and
|
||||
* yes/no button labels can be changed.</p>
|
||||
*
|
||||
* <p>Finally, you can use {@link #addExtra(String, Object)} to add more parameters to the Intent used
|
||||
* to invoke the scanner. This can be used to set additional options not directly exposed by this
|
||||
* simplified API.</p>
|
||||
*
|
||||
* <p>By default, this will only allow applications that are known to respond to this intent correctly
|
||||
* do so. The apps that are allowed to response can be set with {@link #setTargetApplications(List)}.
|
||||
* For example, set to {@link #TARGET_BARCODE_SCANNER_ONLY} to only target the Barcode Scanner app itself.</p>
|
||||
*
|
||||
* <h2>Sharing text via barcode</h2>
|
||||
*
|
||||
* <p>To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(CharSequence)}.</p>
|
||||
*
|
||||
* <p>Some code, particularly download integration, was contributed from the Anobiit application.</p>
|
||||
*
|
||||
* <h2>Enabling experimental barcode formats</h2>
|
||||
*
|
||||
* <p>Some formats are not enabled by default even when scanning with {@link #ALL_CODE_TYPES}, such as
|
||||
* PDF417. Use {@link #initiateScan(java.util.Collection)} with
|
||||
* a collection containing the names of formats to scan for explicitly, like "PDF_417", to use such
|
||||
* formats.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author Fred Lin
|
||||
* @author Isaac Potoczny-Jones
|
||||
* @author Brad Drehmer
|
||||
* @author gcstang
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class IntentIntegrator {
|
||||
|
||||
public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits
|
||||
|
||||
public static final String DEFAULT_TITLE = "Install Barcode Scanner?";
|
||||
public static final String DEFAULT_MESSAGE =
|
||||
"This application requires a Barcode Scanner. Would you like to install one?";
|
||||
public static final String DEFAULT_YES = "Yes";
|
||||
public static final String DEFAULT_NO = "No";
|
||||
|
||||
private static final String BS_PACKAGE = "com.google.zxing.client.android";
|
||||
|
||||
// supported barcode formats
|
||||
public static final Collection<String> PRODUCT_CODE_TYPES = list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "RSS_14");
|
||||
public static final Collection<String> ONE_D_CODE_TYPES =
|
||||
list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "CODE_39", "CODE_93", "CODE_128",
|
||||
"ITF", "RSS_14", "RSS_EXPANDED");
|
||||
public static final Collection<String> QR_CODE_TYPES = Collections.singleton("QR_CODE");
|
||||
public static final Collection<String> DATA_MATRIX_TYPES = Collections.singleton("DATA_MATRIX");
|
||||
|
||||
public static final Collection<String> ALL_CODE_TYPES = null;
|
||||
|
||||
public static final List<String> TARGET_BARCODE_SCANNER_ONLY = Collections.singletonList(BS_PACKAGE);
|
||||
|
||||
private final AppCompatActivity activity;
|
||||
private final Fragment fragment;
|
||||
|
||||
private String title;
|
||||
private String message;
|
||||
private String buttonYes;
|
||||
private String buttonNo;
|
||||
private final Map<String, Object> moreExtras = new HashMap<>(3);
|
||||
|
||||
/**
|
||||
* @param activity {@link AppCompatActivity} invoking the integration
|
||||
*/
|
||||
public IntentIntegrator(AppCompatActivity activity) {
|
||||
this.activity = activity;
|
||||
this.fragment = null;
|
||||
initializeConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fragment {@link Fragment} invoking the integration.
|
||||
* {@link #startActivityForResult(Intent, int)} will be called on the {@link Fragment} instead
|
||||
* of an {@link AppCompatActivity}
|
||||
*/
|
||||
public IntentIntegrator(Fragment fragment) {
|
||||
this.activity = (AppCompatActivity) fragment.getActivity();
|
||||
this.fragment = fragment;
|
||||
initializeConfiguration();
|
||||
}
|
||||
|
||||
private void initializeConfiguration() {
|
||||
title = DEFAULT_TITLE;
|
||||
message = DEFAULT_MESSAGE;
|
||||
buttonYes = DEFAULT_YES;
|
||||
buttonNo = DEFAULT_NO;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setTitleByID(int titleID) {
|
||||
title = activity.getString(titleID);
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void setMessageByID(int messageID) {
|
||||
message = activity.getString(messageID);
|
||||
}
|
||||
|
||||
public String getButtonYes() {
|
||||
return buttonYes;
|
||||
}
|
||||
|
||||
public void setButtonYes(String buttonYes) {
|
||||
this.buttonYes = buttonYes;
|
||||
}
|
||||
|
||||
public void setButtonYesByID(int buttonYesID) {
|
||||
buttonYes = activity.getString(buttonYesID);
|
||||
}
|
||||
|
||||
public String getButtonNo() {
|
||||
return buttonNo;
|
||||
}
|
||||
|
||||
public void setButtonNo(String buttonNo) {
|
||||
this.buttonNo = buttonNo;
|
||||
}
|
||||
|
||||
public void setButtonNoByID(int buttonNoID) {
|
||||
buttonNo = activity.getString(buttonNoID);
|
||||
}
|
||||
|
||||
public Map<String, ?> getMoreExtras() {
|
||||
return moreExtras;
|
||||
}
|
||||
|
||||
public final void addExtra(String key, Object value) {
|
||||
moreExtras.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a scan for all known barcode types with the default camera.
|
||||
*
|
||||
* @return the {@link AlertDialog} that was shown to the user prompting them to download the app
|
||||
* if a prompt was needed, or null otherwise.
|
||||
*/
|
||||
public final AlertDialog initiateScan() {
|
||||
return initiateScan(ALL_CODE_TYPES, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a scan for all known barcode types with the specified camera.
|
||||
*
|
||||
* @param cameraId camera ID of the camera to use. A negative value means "no preference".
|
||||
* @return the {@link AlertDialog} that was shown to the user prompting them to download the app
|
||||
* if a prompt was needed, or null otherwise.
|
||||
*/
|
||||
public final AlertDialog initiateScan(int cameraId) {
|
||||
return initiateScan(ALL_CODE_TYPES, cameraId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a scan, using the default camera, only for a certain set of barcode types, given as strings corresponding
|
||||
* to their names in ZXing's {@code BarcodeFormat} class like "UPC_A". You can supply constants
|
||||
* like {@link #PRODUCT_CODE_TYPES} for example.
|
||||
*
|
||||
* @param desiredBarcodeFormats names of {@code BarcodeFormat}s to scan for
|
||||
* @return the {@link AlertDialog} that was shown to the user prompting them to download the app
|
||||
* if a prompt was needed, or null otherwise.
|
||||
*/
|
||||
public final AlertDialog initiateScan(Collection<String> desiredBarcodeFormats) {
|
||||
return initiateScan(desiredBarcodeFormats, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a scan, using the specified camera, only for a certain set of barcode types, given as strings corresponding
|
||||
* to their names in ZXing's {@code BarcodeFormat} class like "UPC_A". You can supply constants
|
||||
* like {@link #PRODUCT_CODE_TYPES} for example.
|
||||
*
|
||||
* @param desiredBarcodeFormats names of {@code BarcodeFormat}s to scan for
|
||||
* @param cameraId camera ID of the camera to use. A negative value means "no preference".
|
||||
* @return the {@link AlertDialog} that was shown to the user prompting them to download the app
|
||||
* if a prompt was needed, or null otherwise
|
||||
*/
|
||||
public final AlertDialog initiateScan(Collection<String> desiredBarcodeFormats, int cameraId) {
|
||||
Intent intentScan = new Intent(BS_PACKAGE + ".SCAN");
|
||||
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
|
||||
// check which types of codes to scan for
|
||||
if (desiredBarcodeFormats != null) {
|
||||
// set the desired barcode types
|
||||
StringBuilder joinedByComma = new StringBuilder();
|
||||
for (String format : desiredBarcodeFormats) {
|
||||
if (joinedByComma.length() > 0) {
|
||||
joinedByComma.append(',');
|
||||
}
|
||||
joinedByComma.append(format);
|
||||
}
|
||||
intentScan.putExtra("SCAN_FORMATS", joinedByComma.toString());
|
||||
}
|
||||
|
||||
// check requested camera ID
|
||||
if (cameraId >= 0) {
|
||||
intentScan.putExtra("SCAN_CAMERA_ID", cameraId);
|
||||
}
|
||||
|
||||
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
attachMoreExtras(intentScan);
|
||||
try {
|
||||
startActivityForResult(intentScan, REQUEST_CODE);
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
return showDownloadDialog();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start an activity. This method is defined to allow different methods of activity starting for
|
||||
* newer versions of Android and for compatibility library.
|
||||
*
|
||||
* @param intent Intent to start.
|
||||
* @param code Request code for the activity
|
||||
* @see android.app.AppCompatActivity#startActivityForResult(Intent, int)
|
||||
* @see Fragment#startActivityForResult(Intent, int)
|
||||
*/
|
||||
protected void startActivityForResult(Intent intent, int code) {
|
||||
if (fragment == null) {
|
||||
activity.startActivityForResult(intent, code);
|
||||
} else {
|
||||
fragment.startActivityForResult(intent, code);
|
||||
}
|
||||
}
|
||||
|
||||
private AlertDialog showDownloadDialog() {
|
||||
AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
|
||||
downloadDialog.setTitle(title);
|
||||
downloadDialog.setMessage(message);
|
||||
downloadDialog.setPositiveButton(buttonYes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
String packageName = BS_PACKAGE;
|
||||
Uri uri = Uri.parse("market://details?id=" + packageName);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
if (fragment == null) {
|
||||
activity.startActivity(intent);
|
||||
} else {
|
||||
fragment.startActivity(intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
downloadDialog.setNegativeButton(buttonNo, null);
|
||||
downloadDialog.setCancelable(true);
|
||||
return downloadDialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Call this from your {@link AppCompatActivity}'s
|
||||
* {@link AppCompatActivity#onActivityResult(int, int, Intent)} method.</p>
|
||||
*
|
||||
* @param requestCode request code from {@code onActivityResult()}
|
||||
* @param resultCode result code from {@code onActivityResult()}
|
||||
* @param intent {@link Intent} from {@code onActivityResult()}
|
||||
* @return null if the event handled here was not related to this class, or
|
||||
* else an {@link IntentResult} containing the result of the scan. If the user cancelled scanning,
|
||||
* the fields will be null.
|
||||
*/
|
||||
public static IntentResult parseActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
if (requestCode == REQUEST_CODE) {
|
||||
if (resultCode == AppCompatActivity.RESULT_OK) {
|
||||
String contents = intent.getStringExtra("SCAN_RESULT");
|
||||
String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT");
|
||||
byte[] rawBytes = intent.getByteArrayExtra("SCAN_RESULT_BYTES");
|
||||
int intentOrientation = intent.getIntExtra("SCAN_RESULT_ORIENTATION", Integer.MIN_VALUE);
|
||||
Integer orientation = intentOrientation == Integer.MIN_VALUE ? null : intentOrientation;
|
||||
String errorCorrectionLevel = intent.getStringExtra("SCAN_RESULT_ERROR_CORRECTION_LEVEL");
|
||||
return new IntentResult(contents,
|
||||
formatName,
|
||||
rawBytes,
|
||||
orientation,
|
||||
errorCorrectionLevel);
|
||||
}
|
||||
return new IntentResult();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defaults to type "TEXT_TYPE".
|
||||
*
|
||||
* @param text the text string to encode as a barcode
|
||||
* @return the {@link AlertDialog} that was shown to the user prompting them to download the app
|
||||
* if a prompt was needed, or null otherwise
|
||||
* @see #shareText(CharSequence, CharSequence)
|
||||
*/
|
||||
public final AlertDialog shareText(CharSequence text) {
|
||||
return shareText(text, "TEXT_TYPE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares the given text by encoding it as a barcode, such that another user can
|
||||
* scan the text off the screen of the device.
|
||||
*
|
||||
* @param text the text string to encode as a barcode
|
||||
* @param type type of data to encode. See {@code com.google.zxing.client.android.Contents.Type} constants.
|
||||
* @return the {@link AlertDialog} that was shown to the user prompting them to download the app
|
||||
* if a prompt was needed, or null otherwise
|
||||
*/
|
||||
public final AlertDialog shareText(CharSequence text, CharSequence type) {
|
||||
Intent intent = new Intent();
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
intent.setAction(BS_PACKAGE + ".ENCODE");
|
||||
intent.putExtra("ENCODE_TYPE", type);
|
||||
intent.putExtra("ENCODE_DATA", text);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
attachMoreExtras(intent);
|
||||
try {
|
||||
if (fragment == null) {
|
||||
activity.startActivity(intent);
|
||||
} else {
|
||||
fragment.startActivity(intent);
|
||||
}
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
return showDownloadDialog();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<String> list(String... values) {
|
||||
return Collections.unmodifiableList(Arrays.asList(values));
|
||||
}
|
||||
|
||||
private void attachMoreExtras(Intent intent) {
|
||||
for (Map.Entry<String, Object> entry : moreExtras.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
// Kind of hacky
|
||||
if (value instanceof Integer) {
|
||||
intent.putExtra(key, (Integer) value);
|
||||
} else if (value instanceof Long) {
|
||||
intent.putExtra(key, (Long) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
intent.putExtra(key, (Boolean) value);
|
||||
} else if (value instanceof Double) {
|
||||
intent.putExtra(key, (Double) value);
|
||||
} else if (value instanceof Float) {
|
||||
intent.putExtra(key, (Float) value);
|
||||
} else if (value instanceof Bundle) {
|
||||
intent.putExtra(key, (Bundle) value);
|
||||
} else {
|
||||
intent.putExtra(key, value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.integration.android;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates the result of a barcode scan invoked through {@link IntentIntegrator}.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class IntentResult {
|
||||
|
||||
private final String contents;
|
||||
private final String formatName;
|
||||
private final byte[] rawBytes;
|
||||
private final Integer orientation;
|
||||
private final String errorCorrectionLevel;
|
||||
|
||||
IntentResult() {
|
||||
this(null, null, null, null, null);
|
||||
}
|
||||
|
||||
IntentResult(String contents,
|
||||
String formatName,
|
||||
byte[] rawBytes,
|
||||
Integer orientation,
|
||||
String errorCorrectionLevel) {
|
||||
this.contents = contents;
|
||||
this.formatName = formatName;
|
||||
this.rawBytes = rawBytes;
|
||||
this.orientation = orientation;
|
||||
this.errorCorrectionLevel = errorCorrectionLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return raw content of barcode
|
||||
*/
|
||||
public String getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of format, like "QR_CODE", "UPC_A". See {@code BarcodeFormat} for more format names.
|
||||
*/
|
||||
public String getFormatName() {
|
||||
return formatName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return raw bytes of the barcode content, if applicable, or null otherwise
|
||||
*/
|
||||
public byte[] getRawBytes() {
|
||||
return rawBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return rotation of the image, in degrees, which resulted in a successful scan. May be null.
|
||||
*/
|
||||
public Integer getOrientation() {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of the error correction level used in the barcode, if applicable
|
||||
*/
|
||||
public String getErrorCorrectionLevel() {
|
||||
return errorCorrectionLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
int rawBytesLength = rawBytes == null ? 0 : rawBytes.length;
|
||||
return "Format: " + formatName + '\n' + "Contents: " + contents + '\n' + "Raw bytes: (" + rawBytesLength
|
||||
+ " bytes)\n" + "Orientation: " + orientation + '\n' + "EC level: " + errorCorrectionLevel + '\n';
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,7 @@ import org.fdroid.fdroid.nearby.PublicSourceDirProvider;
|
||||
import org.fdroid.fdroid.nearby.SDCardScannerService;
|
||||
import org.fdroid.fdroid.nearby.WifiStateChangeService;
|
||||
import org.fdroid.fdroid.net.ConnectivityMonitorService;
|
||||
import org.fdroid.fdroid.net.DownloaderFactory;
|
||||
import org.fdroid.fdroid.panic.HidingManager;
|
||||
import org.fdroid.fdroid.receiver.DeviceStorageReceiver;
|
||||
import org.fdroid.fdroid.work.CleanCacheWorker;
|
||||
@@ -508,7 +509,8 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
|
||||
|
||||
public static Repository createSwapRepo(String address, String certificate) {
|
||||
long now = System.currentTimeMillis();
|
||||
return new Repository(42L, address, now, IndexFormatVersion.ONE, certificate, 20001L, 42, now);
|
||||
return new Repository(42L, address, now, IndexFormatVersion.ONE, certificate, 20001L, 42,
|
||||
now);
|
||||
}
|
||||
|
||||
public static Context getInstance() {
|
||||
@@ -516,7 +518,10 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
|
||||
}
|
||||
|
||||
public static RepoManager getRepoManager(Context context) {
|
||||
if (repoManager == null) repoManager = new RepoManager(DBHelper.getDb(context));
|
||||
if (repoManager == null) {
|
||||
repoManager = new RepoManager(context, DBHelper.getDb(context), DownloaderFactory.INSTANCE,
|
||||
DownloaderFactory.HTTP_MANAGER);
|
||||
}
|
||||
return repoManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -402,7 +402,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
|
||||
return Theme.valueOf(preferences.getString(Preferences.PREF_THEME, null));
|
||||
}
|
||||
|
||||
boolean isPureBlack() {
|
||||
public boolean isPureBlack() {
|
||||
return preferences.getBoolean(Preferences.PREF_USE_PURE_BLACK_DARK_THEME, false);
|
||||
}
|
||||
|
||||
|
||||
102
app/src/main/java/org/fdroid/fdroid/compose/ComposeUtils.kt
Normal file
102
app/src/main/java/org/fdroid/fdroid/compose/ComposeUtils.kt
Normal file
@@ -0,0 +1,102 @@
|
||||
package org.fdroid.fdroid.compose
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.OutlinedButton
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.em
|
||||
import com.google.accompanist.themeadapter.material.createMdcTheme
|
||||
import org.fdroid.fdroid.Preferences
|
||||
import java.util.Locale
|
||||
|
||||
object ComposeUtils {
|
||||
@Composable
|
||||
fun FDroidContent(content: @Composable () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
val (colors, typography, shapes) = createMdcTheme(
|
||||
context = context,
|
||||
layoutDirection = layoutDirection,
|
||||
)
|
||||
val newColors = (colors ?: MaterialTheme.colors).let { c ->
|
||||
if (!c.isLight && Preferences.get().isPureBlack) c.copy(background = Color.Black)
|
||||
else c
|
||||
}
|
||||
MaterialTheme(
|
||||
colors = newColors,
|
||||
typography = typography?.let {
|
||||
// adapt letter-spacing to non-compose UI
|
||||
it.copy(
|
||||
body1 = it.body1.copy(letterSpacing = 0.em),
|
||||
body2 = it.body2.copy(letterSpacing = 0.em),
|
||||
)
|
||||
} ?: MaterialTheme.typography,
|
||||
shapes = shapes ?: MaterialTheme.shapes
|
||||
) {
|
||||
Surface(content = content)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FDroidButton(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
imageVector: ImageVector? = null,
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
shape = RoundedCornerShape(32.dp),
|
||||
modifier = modifier.heightIn(min = ButtonDefaults.MinHeight)
|
||||
) {
|
||||
if (imageVector != null) {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = text,
|
||||
modifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
|
||||
}
|
||||
Text(text = text.uppercase(Locale.getDefault()))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FDroidOutlineButton(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
imageVector: ImageVector? = null,
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = onClick,
|
||||
shape = RoundedCornerShape(32.dp),
|
||||
modifier = modifier.heightIn(min = ButtonDefaults.MinHeight)
|
||||
) {
|
||||
if (imageVector != null) {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = text,
|
||||
modifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
|
||||
}
|
||||
Text(text = text.uppercase(Locale.getDefault()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,6 +63,7 @@ import org.fdroid.database.RepositoryDao;
|
||||
import org.fdroid.download.Mirror;
|
||||
import org.fdroid.fdroid.AddRepoIntentService;
|
||||
import org.fdroid.fdroid.AppUpdateStatusManager;
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
@@ -71,6 +72,7 @@ import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.DBHelper;
|
||||
import org.fdroid.fdroid.data.NewRepoConfig;
|
||||
import org.fdroid.fdroid.views.repos.AddRepoActivity;
|
||||
import org.fdroid.index.RepoManager;
|
||||
import org.fdroid.index.v1.IndexV1UpdaterKt;
|
||||
|
||||
@@ -134,7 +136,13 @@ public class ManageReposActivity extends AppCompatActivity implements RepoAdapte
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
toolbar.setOnMenuItemClickListener(menuItem -> {
|
||||
if (menuItem.getItemId() == R.id.action_add_repo) {
|
||||
showAddRepo();
|
||||
if (BuildConfig.DEBUG) {
|
||||
// TODO enable this for all builds and remove dead code afterwards
|
||||
Intent i = new Intent(this, AddRepoActivity.class);
|
||||
startActivity(i);
|
||||
} else {
|
||||
showAddRepo();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.fdroid.fdroid.views.repos
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.lifecycle.Lifecycle.State.STARTED
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fdroid.fdroid.FDroidApp
|
||||
import org.fdroid.fdroid.UpdateService
|
||||
import org.fdroid.fdroid.compose.ComposeUtils.FDroidContent
|
||||
import org.fdroid.fdroid.views.ManageReposActivity
|
||||
import org.fdroid.repo.AddRepoError
|
||||
import org.fdroid.repo.Added
|
||||
|
||||
class AddRepoActivity : ComponentActivity() {
|
||||
|
||||
private val repoManager = FDroidApp.getRepoManager(this)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(STARTED) {
|
||||
repoManager.addRepoState.collect { state ->
|
||||
if (state is Added) {
|
||||
// update newly added repo
|
||||
UpdateService.updateRepoNow(applicationContext, state.repo.address)
|
||||
// show repo list and close this activity
|
||||
val intent = Intent(applicationContext, ManageReposActivity::class.java)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setContent {
|
||||
FDroidContent {
|
||||
val state = repoManager.addRepoState.collectAsState().value
|
||||
BackHandler(state is AddRepoError) {
|
||||
// reset state when going back on error screen
|
||||
repoManager.abortAddingRepository()
|
||||
}
|
||||
AddRepoIntroScreen(
|
||||
state = state,
|
||||
onFetchRepo = { url ->
|
||||
repoManager.fetchRepositoryPreview(url)
|
||||
},
|
||||
onAddRepo = { repoManager.addFetchedRepository() },
|
||||
onBackClicked = { onBackPressedDispatcher.onBackPressed() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
if (!isChangingConfigurations) repoManager.abortAddingRepository()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.fdroid.fdroid.views.repos
|
||||
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Error
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.fdroid.fdroid.R
|
||||
import org.fdroid.fdroid.compose.ComposeUtils
|
||||
import org.fdroid.fdroid.views.ManageReposActivity.getDisallowInstallUnknownSourcesErrorMessage
|
||||
import org.fdroid.repo.AddRepoError
|
||||
import org.fdroid.repo.AddRepoError.ErrorType.INVALID_FINGERPRINT
|
||||
import org.fdroid.repo.AddRepoError.ErrorType.INVALID_INDEX
|
||||
import org.fdroid.repo.AddRepoError.ErrorType.IO_ERROR
|
||||
import org.fdroid.repo.AddRepoError.ErrorType.UNKNOWN_SOURCES_DISALLOWED
|
||||
import java.io.IOException
|
||||
|
||||
@Composable
|
||||
fun AddRepoErrorScreen(paddingValues: PaddingValues, state: AddRepoError) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp, CenterVertically),
|
||||
horizontalAlignment = CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
Image(
|
||||
imageVector = Icons.Default.Error,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colors.error),
|
||||
modifier = Modifier.size(48.dp),
|
||||
)
|
||||
val title = when (state.errorType) {
|
||||
INVALID_FINGERPRINT -> stringResource(R.string.bad_fingerprint)
|
||||
UNKNOWN_SOURCES_DISALLOWED -> {
|
||||
val context = LocalContext.current
|
||||
getDisallowInstallUnknownSourcesErrorMessage(context)
|
||||
}
|
||||
|
||||
INVALID_INDEX -> stringResource(R.string.repo_invalid)
|
||||
IO_ERROR -> stringResource(R.string.repo_io_error)
|
||||
}
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.h5,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
if (state.exception != null) Text(
|
||||
text = state.exception.toString(),
|
||||
style = MaterialTheme.typography.body1,
|
||||
modifier = Modifier.alpha(ContentAlpha.medium),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AddRepoErrorInvalidFingerprintPreview() {
|
||||
ComposeUtils.FDroidContent {
|
||||
AddRepoErrorScreen(PaddingValues(0.dp), AddRepoError(INVALID_FINGERPRINT))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AddRepoErrorIoErrorPreview() {
|
||||
ComposeUtils.FDroidContent {
|
||||
AddRepoErrorScreen(PaddingValues(0.dp), AddRepoError(IO_ERROR, IOException("foo bar")))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AddRepoErrorInvalidIndexPreview() {
|
||||
ComposeUtils.FDroidContent {
|
||||
AddRepoErrorScreen(
|
||||
PaddingValues(0.dp),
|
||||
AddRepoError(INVALID_INDEX, RuntimeException("foo bar"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AddRepoErrorUnknownSourcesPreview() {
|
||||
ComposeUtils.FDroidContent {
|
||||
AddRepoErrorScreen(PaddingValues(0.dp), AddRepoError(UNKNOWN_SOURCES_DISALLOWED))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package org.fdroid.fdroid.views.repos
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
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.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.ArrowDropUp
|
||||
import androidx.compose.material.icons.filled.ContentPaste
|
||||
import androidx.compose.material.icons.filled.QrCode
|
||||
import androidx.compose.material.primarySurface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
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.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.zxing.client.android.Intents.Scan.MIXED_SCAN
|
||||
import com.google.zxing.client.android.Intents.Scan.SCAN_TYPE
|
||||
import com.journeyapps.barcodescanner.ScanContract
|
||||
import com.journeyapps.barcodescanner.ScanOptions
|
||||
import com.journeyapps.barcodescanner.ScanOptions.QR_CODE
|
||||
import org.fdroid.fdroid.R
|
||||
import org.fdroid.fdroid.compose.ComposeUtils.FDroidButton
|
||||
import org.fdroid.fdroid.compose.ComposeUtils.FDroidContent
|
||||
import org.fdroid.fdroid.compose.ComposeUtils.FDroidOutlineButton
|
||||
import org.fdroid.repo.AddRepoError
|
||||
import org.fdroid.repo.AddRepoState
|
||||
import org.fdroid.repo.Added
|
||||
import org.fdroid.repo.Adding
|
||||
import org.fdroid.repo.Fetching
|
||||
import org.fdroid.repo.None
|
||||
|
||||
@Composable
|
||||
fun AddRepoIntroScreen(
|
||||
state: AddRepoState,
|
||||
onFetchRepo: (String) -> Unit,
|
||||
onAddRepo: () -> Unit,
|
||||
onBackClicked: () -> Unit,
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
TopAppBar(
|
||||
elevation = 4.dp,
|
||||
backgroundColor = MaterialTheme.colors.primarySurface,
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBackClicked) {
|
||||
Icon(Icons.Filled.ArrowBack, stringResource(R.string.back))
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.repo_add_title),
|
||||
modifier = Modifier.alpha(ContentAlpha.high),
|
||||
)
|
||||
},
|
||||
)
|
||||
}) { paddingValues ->
|
||||
when (state) {
|
||||
None -> AddRepoIntroContent(paddingValues, onFetchRepo)
|
||||
is Fetching -> {
|
||||
if (state.repo == null) {
|
||||
RepoProgressScreen(paddingValues, stringResource(R.string.repo_state_fetching))
|
||||
} else {
|
||||
RepoPreviewScreen(paddingValues, state, onAddRepo)
|
||||
}
|
||||
}
|
||||
|
||||
Adding -> RepoProgressScreen(paddingValues, stringResource(R.string.repo_state_adding))
|
||||
is Added -> Box(modifier = Modifier.padding(paddingValues)) // empty UI
|
||||
is AddRepoError -> AddRepoErrorScreen(paddingValues, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddRepoIntroContent(paddingValues: PaddingValues, onFetchRepo: (String) -> Unit) {
|
||||
Column(
|
||||
verticalArrangement = spacedBy(16.dp),
|
||||
horizontalAlignment = CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp)
|
||||
.padding(paddingValues),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.repo_intro),
|
||||
style = MaterialTheme.typography.body1,
|
||||
)
|
||||
val startForResult = rememberLauncherForActivityResult(ScanContract()) { result ->
|
||||
if (result.contents != null) {
|
||||
onFetchRepo(result.contents)
|
||||
}
|
||||
}
|
||||
FDroidButton(
|
||||
"Scan QR code",
|
||||
imageVector = Icons.Filled.QrCode,
|
||||
onClick = {
|
||||
startForResult.launch(ScanOptions().apply {
|
||||
setPrompt("")
|
||||
setBeepEnabled(true)
|
||||
setOrientationLocked(false)
|
||||
setDesiredBarcodeFormats(QR_CODE)
|
||||
addExtra(SCAN_TYPE, MIXED_SCAN)
|
||||
})
|
||||
},
|
||||
)
|
||||
val isPreview = LocalInspectionMode.current
|
||||
var manualExpanded by rememberSaveable { mutableStateOf(isPreview) }
|
||||
Row(
|
||||
horizontalArrangement = spacedBy(16.dp),
|
||||
verticalAlignment = CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = ButtonDefaults.MinHeight)
|
||||
.clickable { manualExpanded = !manualExpanded },
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.repo_enter_url)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Icon(
|
||||
imageVector = if (manualExpanded) {
|
||||
Icons.Default.ArrowDropUp
|
||||
} else {
|
||||
Icons.Default.ArrowDropDown
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
val textState = remember { mutableStateOf(TextFieldValue()) }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
AnimatedVisibility(visible = manualExpanded) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.End,
|
||||
verticalArrangement = spacedBy(16.dp),
|
||||
) {
|
||||
TextField(
|
||||
value = textState.value,
|
||||
minLines = 2,
|
||||
onValueChange = { textState.value = it },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequester)
|
||||
.onGloballyPositioned {
|
||||
focusRequester.requestFocus()
|
||||
},
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = spacedBy(16.dp),
|
||||
verticalAlignment = CenterVertically,
|
||||
) {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
FDroidOutlineButton(
|
||||
"Paste",
|
||||
imageVector = Icons.Default.ContentPaste,
|
||||
onClick = {
|
||||
if (clipboardManager.hasText()) {
|
||||
textState.value =
|
||||
TextFieldValue(clipboardManager.getText()?.text ?: "")
|
||||
}
|
||||
},
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
FDroidButton(
|
||||
text = stringResource(R.string.repo_add_add),
|
||||
onClick = { onFetchRepo(textState.value.text) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun AddRepoIntroScreenPreview() {
|
||||
FDroidContent {
|
||||
AddRepoIntroScreen(None, {}, {}) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES, widthDp = 720, heightDp = 360)
|
||||
fun AddRepoIntroScreenPreviewNight() {
|
||||
FDroidContent {
|
||||
AddRepoIntroScreen(None, {}, {}) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
package org.fdroid.fdroid.views.repos
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyItemScope
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Alignment.Companion.End
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.datasource.LoremIpsum
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.res.ResourcesCompat.getDrawable
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
|
||||
import com.bumptech.glide.integration.compose.GlideImage
|
||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||
import org.fdroid.database.MinimalApp
|
||||
import org.fdroid.database.Repository
|
||||
import org.fdroid.fdroid.FDroidApp
|
||||
import org.fdroid.fdroid.R
|
||||
import org.fdroid.fdroid.Utils
|
||||
import org.fdroid.fdroid.Utils.getDownloadRequest
|
||||
import org.fdroid.fdroid.compose.ComposeUtils.FDroidButton
|
||||
import org.fdroid.fdroid.compose.ComposeUtils.FDroidContent
|
||||
import org.fdroid.index.v2.FileV2
|
||||
import org.fdroid.repo.FetchResult.IsExistingRepository
|
||||
import org.fdroid.repo.FetchResult.IsNewMirror
|
||||
import org.fdroid.repo.FetchResult.IsNewRepository
|
||||
import org.fdroid.repo.Fetching
|
||||
|
||||
@Composable
|
||||
fun RepoPreviewScreen(paddingValues: PaddingValues, state: Fetching, onAddRepo: () -> Unit) {
|
||||
val isPreview = LocalInspectionMode.current
|
||||
val localeList = LocaleListCompat.getDefault()
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
verticalArrangement = spacedBy(8.dp),
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
item {
|
||||
RepoPreviewHeader(state, onAddRepo, localeList, isPreview)
|
||||
}
|
||||
if (state.fetchResult == null || state.fetchResult is IsNewRepository) {
|
||||
item {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
horizontalArrangement = spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Included apps:",
|
||||
style = MaterialTheme.typography.body1,
|
||||
)
|
||||
Text(
|
||||
text = state.apps.size.toString(),
|
||||
style = MaterialTheme.typography.body1,
|
||||
)
|
||||
if (!state.done) LinearProgressIndicator(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
items(items = state.apps, key = { it.packageName }) { app ->
|
||||
RepoPreviewApp(state.repo ?: error("no repo"), app, localeList, isPreview)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalGlideComposeApi::class)
|
||||
fun RepoPreviewHeader(
|
||||
state: Fetching,
|
||||
onAddRepo: () -> Unit,
|
||||
localeList: LocaleListCompat,
|
||||
isPreview: Boolean,
|
||||
) {
|
||||
Column(verticalArrangement = spacedBy(8.dp)) {
|
||||
val repo = state.repo ?: error("repo was null")
|
||||
val res = LocalContext.current.resources
|
||||
Row(
|
||||
horizontalArrangement = spacedBy(8.dp),
|
||||
verticalAlignment = CenterVertically,
|
||||
) {
|
||||
if (isPreview) Image(
|
||||
painter = rememberDrawablePainter(
|
||||
getDrawable(res, R.drawable.ic_launcher, null)
|
||||
),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(48.dp),
|
||||
) else GlideImage(
|
||||
model = getDownloadRequest(repo, repo.getIcon(localeList)),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(48.dp),
|
||||
) {
|
||||
it.fallback(R.drawable.ic_repo_app_default).error(R.drawable.ic_repo_app_default)
|
||||
}
|
||||
Column(horizontalAlignment = Alignment.Start) {
|
||||
Text(
|
||||
text = repo.getName(localeList) ?: "Unknown Repository",
|
||||
maxLines = 1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
style = MaterialTheme.typography.body1,
|
||||
)
|
||||
Text(
|
||||
text = repo.address.replaceFirst("https://", ""),
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.alpha(ContentAlpha.medium),
|
||||
)
|
||||
Text(
|
||||
text = Utils.formatLastUpdated(res, repo.timestamp),
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (state.canAdd) FDroidButton(
|
||||
text = when (state.fetchResult) {
|
||||
IsNewRepository -> stringResource(R.string.repo_add_new_title)
|
||||
is IsNewMirror -> stringResource(R.string.repo_add_new_mirror)
|
||||
else -> error("Unexpected fetch state: ${state.fetchResult}")
|
||||
},
|
||||
onClick = onAddRepo,
|
||||
modifier = Modifier.align(End)
|
||||
) else if (state.fetchResult is IsExistingRepository) {
|
||||
Text(
|
||||
text = stringResource(R.string.repo_exists),
|
||||
style = MaterialTheme.typography.body1,
|
||||
color = MaterialTheme.colors.error,
|
||||
)
|
||||
}
|
||||
val description = if (isPreview) {
|
||||
LoremIpsum(42).values.joinToString(" ")
|
||||
} else {
|
||||
repo.getDescription(localeList)
|
||||
}
|
||||
if (description != null) Text(
|
||||
text = description,
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalGlideComposeApi::class, ExperimentalFoundationApi::class)
|
||||
fun LazyItemScope.RepoPreviewApp(
|
||||
repo: Repository,
|
||||
app: MinimalApp,
|
||||
localeList: LocaleListCompat,
|
||||
isPreview: Boolean,
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.animateItemPlacement()
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = spacedBy(8.dp),
|
||||
modifier = Modifier.padding(8.dp),
|
||||
) {
|
||||
if (isPreview) Image(
|
||||
painter = rememberDrawablePainter(
|
||||
getDrawable(LocalContext.current.resources, R.drawable.ic_launcher, null)
|
||||
),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(38.dp),
|
||||
) else GlideImage(
|
||||
model = getDownloadRequest(repo, app.getIcon(localeList)),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(38.dp),
|
||||
) {
|
||||
it.fallback(R.drawable.ic_repo_app_default).error(R.drawable.ic_repo_app_default)
|
||||
}
|
||||
Column {
|
||||
Text(
|
||||
app.name ?: "Unknown app",
|
||||
style = MaterialTheme.typography.body1,
|
||||
)
|
||||
Text(
|
||||
app.summary ?: "",
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RepoPreviewScreenFetchingPreview() {
|
||||
val repo = FDroidApp.createSwapRepo("https://example.org", "foo bar")
|
||||
val app1 = object : MinimalApp {
|
||||
override val repoId = 0L
|
||||
override val packageName = "org.example"
|
||||
override val name: String = "App 1 with a long name"
|
||||
override val summary: String = "Summary of App1 which can also be a bit longer"
|
||||
override fun getIcon(localeList: LocaleListCompat): FileV2? = null
|
||||
}
|
||||
val app2 = object : MinimalApp {
|
||||
override val repoId = 0L
|
||||
override val packageName = "com.example"
|
||||
override val name: String = "App 2 with a name that is even longer than the first app"
|
||||
override val summary: String =
|
||||
"Summary of App2 which can also be a bit longer, even longer than other apps."
|
||||
|
||||
override fun getIcon(localeList: LocaleListCompat): FileV2? = null
|
||||
}
|
||||
val app3 = object : MinimalApp {
|
||||
override val repoId = 0L
|
||||
override val packageName = "net.example"
|
||||
override val name: String = "App 3"
|
||||
override val summary: String = "short summary"
|
||||
|
||||
override fun getIcon(localeList: LocaleListCompat): FileV2? = null
|
||||
}
|
||||
FDroidContent {
|
||||
RepoPreviewScreen(
|
||||
PaddingValues(0.dp),
|
||||
Fetching(repo, listOf(app1, app2, app3), IsNewRepository)
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RepoPreviewScreenNewMirrorPreview() {
|
||||
val repo = FDroidApp.createSwapRepo("https://example.org", "foo bar")
|
||||
FDroidContent {
|
||||
RepoPreviewScreen(
|
||||
PaddingValues(0.dp),
|
||||
Fetching(repo, emptyList(), IsNewMirror(0L, "foo"))
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RepoPreviewScreenExistingRepoPreview() {
|
||||
val repo = FDroidApp.createSwapRepo("https://example.org", "foo bar")
|
||||
FDroidContent {
|
||||
RepoPreviewScreen(PaddingValues(0.dp), Fetching(repo, emptyList(), IsExistingRepository)) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.fdroid.fdroid.views.repos
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.fdroid.fdroid.R
|
||||
import org.fdroid.fdroid.compose.ComposeUtils.FDroidContent
|
||||
|
||||
@Composable
|
||||
fun RepoProgressScreen(paddingValues: PaddingValues, text: String) {
|
||||
Column(
|
||||
verticalArrangement = spacedBy(16.dp, CenterVertically),
|
||||
horizontalAlignment = CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.h5,
|
||||
)
|
||||
CircularProgressIndicator(modifier = Modifier.size(64.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun FetchingRepoScreenPreview() {
|
||||
FDroidContent {
|
||||
RepoProgressScreen(PaddingValues(0.dp), stringResource(R.string.repo_state_fetching))
|
||||
}
|
||||
}
|
||||
@@ -171,8 +171,10 @@ This often occurs with apps installed via Google Play or other sources, if they
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="repo_add_title">Add new repository</string>
|
||||
<string name="repo_add_new_title">Add repository</string>
|
||||
<string name="repo_add_add">Add</string>
|
||||
<string name="repo_add_mirror">Add mirror</string>
|
||||
<string name="repo_add_new_mirror">Add as new mirror</string>
|
||||
<string name="links">Links</string>
|
||||
<string name="versions">Versions</string>
|
||||
<string name="more">More</string>
|
||||
@@ -190,13 +192,20 @@ This often occurs with apps installed via Google Play or other sources, if they
|
||||
<string name="bluetooth_activity_not_found">No Bluetooth send method found, choose one!</string>
|
||||
<string name="choose_bt_send">Choose Bluetooth send method</string>
|
||||
|
||||
<string name="repo_intro">A repository is an additional source of apps. Third-party ones you add here have different standards than those providing apps built by F-Droid itself.\n\nPlease ensure that the repository you are adding is trustworthy.</string>
|
||||
<string name="repo_state_fetching">Fetching repository…</string>
|
||||
<string name="repo_state_adding">Adding repository…</string>
|
||||
<string name="repo_enter_url">Enter repository URL manually</string>
|
||||
<string name="repo_add_url">Repository address</string>
|
||||
<string name="repo_add_fingerprint">Fingerprint (optional)</string>
|
||||
<string name="repo_exists">This repo was already added.</string>
|
||||
<string name="repo_exists_add_fingerprint">%1$s is already setup, this will add new key information.</string>
|
||||
<string name="repo_exists_enable">%1$s is already setup, confirm that you want to re-enable it.</string>
|
||||
<string name="repo_exists_and_enabled">%1$s is already setup and enabled.</string>
|
||||
<string name="repo_delete_to_overwrite">First delete %1$s in order to add this with a conflicting key.</string>
|
||||
<string name="repo_exists_add_mirror">This is a copy of %1$s, add it as a mirror?</string>
|
||||
<string name="repo_invalid">Invalid repository.\n\nContact the maintainer and let them know about the issue.</string>
|
||||
<string name="repo_io_error">Error connecting to the repository.</string>
|
||||
<string name="bad_fingerprint">Bad fingerprint</string>
|
||||
<string name="invalid_url">This is not a valid URL.</string>
|
||||
<string name="malformed_repo_uri">Ignoring malformed repo URI: %s</string>
|
||||
|
||||
@@ -206,6 +206,16 @@
|
||||
<sha256 value="7f08723ecabefba616d60c714b0e9a31301bd4d0792fcc7946c1479c57fd2d28" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.activity" name="activity" version="1.7.2">
|
||||
<artifact name="activity-1.7.2.aar">
|
||||
<sha256 value="2a1abf8e0a598d246b1edcb71e2395e39f32332195ebe5ea40a3dd21355ba3ae" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.activity" name="activity-compose" version="1.7.2">
|
||||
<artifact name="activity-compose-1.7.2.aar">
|
||||
<sha256 value="c73db26b1672a63f144457271b49cc40380b5bafe60ed0710e82d0a774e36a88" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.activity" name="activity-ktx" version="1.2.2">
|
||||
<artifact name="activity-ktx-1.2.2.aar">
|
||||
<sha256 value="9829e13d6a6b045b03b21a330512e091dc76eb5b3ded0d88d1ab0509cf84a50e" origin="Generated by Gradle"/>
|
||||
@@ -216,6 +226,16 @@
|
||||
<sha256 value="1b46d678f1296d0308b7f1d1fd9c8b2688bd9f8fbddb2929db7f8e503105c68d" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.activity" name="activity-ktx" version="1.7.0">
|
||||
<artifact name="activity-ktx-1.7.0.aar">
|
||||
<sha256 value="fce317d61a22f12967b475bfcb80c89dda66e418975e890ea703cb74e12b5b11" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.activity" name="activity-ktx" version="1.7.2">
|
||||
<artifact name="activity-ktx-1.7.2.aar">
|
||||
<sha256 value="b0b4206ece92919925061fdf5784dd21f0118534609e8f6d9404bdd0f5cb5a3d" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.annotation" name="annotation" version="1.0.0">
|
||||
<artifact name="annotation-1.0.0.jar">
|
||||
<sha256 value="0baae9755f7caf52aa80cd04324b91ba93af55d4d1d17dcc9a7b53d99ef7c016" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -239,6 +259,11 @@
|
||||
<sha256 value="97dc45afefe3a1e421da42b8b6e9f90491477c45fc6178203e3a5e8a05ee8553" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.annotation" name="annotation" version="1.5.0">
|
||||
<artifact name="annotation-1.5.0.jar">
|
||||
<sha256 value="261fb7c0210858500bab66d34354972a75166ab4182add283780b05513d6ec4a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.annotation" name="annotation" version="1.6.0">
|
||||
<artifact name="annotation-metadata-1.6.0.jar">
|
||||
<sha256 value="fbc64f5c44a7added8b6eab517cf7d70555e25153bf5d44a6ed9b0e5312f7de9" origin="Generated by Gradle"/>
|
||||
@@ -387,6 +412,11 @@
|
||||
<sha256 value="48167eeedc8da79c4d29deaf0d0cd9b5d8fedcae01f1a6efb3f28f08e8982f71" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.autofill" name="autofill" version="1.0.0">
|
||||
<artifact name="autofill-1.0.0.aar">
|
||||
<sha256 value="c9468f56e05006ea151a426c54957cd0799b8b83a579d2846dd22061f33e5ecd" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.cardview" name="cardview" version="1.0.0">
|
||||
<artifact name="cardview-1.0.0.aar">
|
||||
<sha256 value="1193c04c22a3d6b5946dae9f4e8c59d6adde6a71b6bd5d87fb99d82dda1afec7" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -416,6 +446,106 @@
|
||||
<sha256 value="2bfc54475c047131913361f56d0f7f019c6e5bee53eeb0eb7d94a7c499a05227" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.animation" name="animation" version="1.4.3">
|
||||
<artifact name="animation-1.4.3.aar">
|
||||
<sha256 value="bc00f44dad4c7b8dc7d73210797c9efacef6b029c8d0a46f50e203bbc9f0f9af" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.animation" name="animation-core" version="1.4.3">
|
||||
<artifact name="animation-core-1.4.3.aar">
|
||||
<sha256 value="d7d949d0a28699d7db5ae5769698255049400378bc8bc041265f85f6686fb2e4" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.compiler" name="compiler" version="1.4.6">
|
||||
<artifact name="compiler-1.4.6.jar">
|
||||
<sha256 value="b10f529d9d83661e3484e173aa4b45775aa625ed7ea7564b6ab116ff65ad2d75" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.foundation" name="foundation" version="1.4.3">
|
||||
<artifact name="foundation-1.4.3.aar">
|
||||
<sha256 value="8316e9c745b534d957fe4e71198e22154267636e3176401dafec7a81599ecd84" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.foundation" name="foundation-layout" version="1.4.3">
|
||||
<artifact name="foundation-layout-1.4.3.aar">
|
||||
<sha256 value="978333f49bbe78d21e20b91a4cd800a0c5eead9876e267e076332b1a87a11c5e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.material" name="material" version="1.4.3">
|
||||
<artifact name="material-1.4.3.aar">
|
||||
<sha256 value="2d9b66b4b19c461293d355906d7cfff161dd155adf7f837323f1b7a4ffd10ca8" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.material" name="material-icons-core" version="1.4.3">
|
||||
<artifact name="material-icons-core-1.4.3.aar">
|
||||
<sha256 value="5ef4030ae792e46fa6866d32c7554347b51afd5820c20c2cd2448d5dd9d20c7b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.material" name="material-icons-extended" version="1.4.3">
|
||||
<artifact name="material-icons-extended-1.4.3.aar">
|
||||
<sha256 value="895ebb8838e04c219481db3bdf773a46a19a2684c2a280d3a9ef57e62c28e180" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.material" name="material-ripple" version="1.4.3">
|
||||
<artifact name="material-ripple-1.4.3.aar">
|
||||
<sha256 value="34e3319f8c3646f000ecb1d6e10ee950d63a6b9d5f92178470669418c1b1ac32" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.runtime" name="runtime" version="1.4.3">
|
||||
<artifact name="runtime-1.4.3.aar">
|
||||
<sha256 value="f975185e13d3e5b0c142e220e924bfe643d4421b0fdae3f2036f1e0160a390f4" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.runtime" name="runtime-saveable" version="1.4.3">
|
||||
<artifact name="runtime-saveable-1.4.3.aar">
|
||||
<sha256 value="756d7f53d64b664ad168c7109aa88cc394fb51aee6a2bb7ac86982242834f5ca" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui" version="1.4.3">
|
||||
<artifact name="ui-1.4.3.aar">
|
||||
<sha256 value="a49acd04ac5d596a1e3b00fd965612901b7d05975c51cc5bcf5258bfc3dbca43" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-geometry" version="1.4.3">
|
||||
<artifact name="ui-geometry-1.4.3.aar">
|
||||
<sha256 value="ef98ec03f6104730c3152f8ea27404f0764c715872f25a1d893879dd4c2e55bd" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-graphics" version="1.4.3">
|
||||
<artifact name="ui-graphics-1.4.3.aar">
|
||||
<sha256 value="298cdc2ff4ea610a22b01f666a460239aa260f2467f7762d575d84e773545b2d" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-text" version="1.4.3">
|
||||
<artifact name="ui-text-1.4.3.aar">
|
||||
<sha256 value="dfa801c2b6b29c97a7f6a20fc45a9b2cb8da4d52b1601d9f10c70878f98f1faa" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-tooling" version="1.4.3">
|
||||
<artifact name="ui-tooling-1.4.3.aar">
|
||||
<sha256 value="e641617b76204f9a03771ee40455553d5ec23d0c1f4a49d1e8177553769b6c06" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-tooling-data" version="1.4.3">
|
||||
<artifact name="ui-tooling-data-1.4.3.aar">
|
||||
<sha256 value="9b9a8d446f1f2bd12157329aba7751755118a659f02cbd7d40afba9ad1e7a61e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-tooling-preview" version="1.4.3">
|
||||
<artifact name="ui-tooling-preview-1.4.3.aar">
|
||||
<sha256 value="7e6316f9439671bc5bd732df93fd3c41433be487f749acae52308101dc8670f7" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-unit" version="1.4.3">
|
||||
<artifact name="ui-unit-1.4.3.aar">
|
||||
<sha256 value="0dfbac9fbf2ca6dce36cd3d990786c9bc09fcfe962cbe27af531311d49611eb4" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.compose.ui" name="ui-util" version="1.4.3">
|
||||
<artifact name="ui-util-1.4.3.aar">
|
||||
<sha256 value="a6ad526f26de348c69f57f1bd8742853ea58b3a22a571fbb76a6d8ba8e620d7e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.concurrent" name="concurrent-futures" version="1.0.0">
|
||||
<artifact name="concurrent-futures-1.0.0.jar">
|
||||
<sha256 value="5595a40e278a7b39fa78a09490e3d7f3faa95c7b01447148bd38b5ade0605c35" origin="Generated by Gradle"/>
|
||||
@@ -656,6 +786,11 @@
|
||||
<sha256 value="f31a06c150ecb03073f55a6f7b0b74a240a6a8d727c14ce76726d020570dfa8c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.emoji2" name="emoji2" version="1.3.0">
|
||||
<artifact name="emoji2-1.3.0.aar">
|
||||
<sha256 value="2bf23818b23a996ddaa1b5fd5bb32129daff6bbb2dce15166e2fccdd2010b1a5" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.emoji2" name="emoji2-views-helper" version="1.0.0">
|
||||
<artifact name="emoji2-views-helper-1.0.0.aar">
|
||||
<sha256 value="39616a3d66551fc18585112ce1d12a14ac0fb588a89a6528cd97842da6221ec2" origin="Generated by Gradle"/>
|
||||
@@ -666,6 +801,11 @@
|
||||
<sha256 value="7ffa4d464d9db259fca0cdb50fbd4ab63d6872bcda59468b9f7555504c7d5ac4" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.emoji2" name="emoji2-views-helper" version="1.3.0">
|
||||
<artifact name="emoji2-views-helper-1.3.0.aar">
|
||||
<sha256 value="9a1351295a4f739df0efe8344adaa9afb34856c3af584d4a9afbec105a45b90b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.exifinterface" name="exifinterface" version="1.2.0">
|
||||
<artifact name="exifinterface-1.2.0.aar">
|
||||
<sha256 value="aae68e513095e475a7670556eacba772ec2bb592d17187091578d3fef947aea7" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -752,6 +892,11 @@
|
||||
<sha256 value="04d525073469214d0c99e81aaa875dd548ba32b82945abd8326bc50229df700d" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-common" version="2.1.0">
|
||||
<artifact name="lifecycle-common-2.1.0.jar">
|
||||
<sha256 value="76db6be533bd730fb361c2feb12a2c26d9952824746847da82601ef81f082643" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-common" version="2.2.0">
|
||||
<artifact name="lifecycle-common-2.2.0.jar">
|
||||
<sha256 value="63898dabf7cfe5ec5d7ed8b8c2564c1427be876e1496ead95c2703cf59d3734b" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -790,6 +935,11 @@
|
||||
<sha256 value="f34831b6c71cd844e1d35d1be49d5e79447c5ab856346531b1e8676fda7374b1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-common-java8" version="2.6.1">
|
||||
<artifact name="lifecycle-common-java8-2.6.1.jar">
|
||||
<sha256 value="c6deada2fac53b8ea6523dbda77597b128006674616f140f04df23264c6d1aa3" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.0.0">
|
||||
<artifact name="lifecycle-livedata-2.0.0.aar">
|
||||
<sha256 value="c82609ced8c498f0a701a30fb6771bb7480860daee84d82e0a81ee86edf7ba39" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -823,6 +973,11 @@
|
||||
<sha256 value="67359f609dfc2bf65da1270b23033f856064ec279f058e0a70c715f7c9003031" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.1.0">
|
||||
<artifact name="lifecycle-livedata-core-2.1.0.aar">
|
||||
<sha256 value="a150743e86c30eddf1660ad454b1f86041efdefcd1a039320c4c26db87f7119a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.2.0">
|
||||
<artifact name="lifecycle-livedata-core-2.2.0.aar">
|
||||
<sha256 value="556c1f3af90aa9d7d0d330565adbf6da71b2429148bac91e07c485f4f9abf614" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -1000,6 +1155,11 @@
|
||||
<sha256 value="e4ff4338999e1c6c9c724719f5d4aa7dd61bf6f545d5256a27a9d375df9f2330" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-compose" version="2.6.1">
|
||||
<artifact name="lifecycle-viewmodel-compose-2.6.1.aar">
|
||||
<sha256 value="c2b820204c2ca58ef9cb015a3e5ffbe88d8c55b09e5cb851d62b445528a379e0" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-ktx" version="2.3.1">
|
||||
<artifact name="lifecycle-viewmodel-ktx-2.3.1.aar">
|
||||
<sha256 value="5fb3591b6a54eeb3e204be0125d48eb987b8ea45a5048140036865482ccf9de9" origin="Generated by Gradle"/>
|
||||
@@ -1371,6 +1531,11 @@
|
||||
<sha256 value="671284e62e393f16ceae1a99a3a9a07bf1aacda29f8fe7b6b884355ef34c09cf" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.test" name="core-ktx" version="1.4.0">
|
||||
<artifact name="core-ktx-1.4.0.aar">
|
||||
<sha256 value="e4f9ca2b8f700cc278d878ed3925730e1ad5d60135bbfd05ab6708a528ebfa58" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.test" name="monitor" version="1.2.0">
|
||||
<artifact name="monitor-1.2.0.aar">
|
||||
<sha256 value="fc97ca3f00f8ca30b7d5167fbd8736756048e2cc4f8e92dc891106751a5baeef" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -3210,6 +3375,11 @@
|
||||
<sha256 value="315b1325283c3d0cf9bc0599c1ecdb85e5f7863b1aa25991b63d616b13930cb6" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.bumptech.glide" name="compose" version="1.0.0-alpha.1">
|
||||
<artifact name="compose-1.0.0-alpha.1.aar">
|
||||
<sha256 value="ce66e14da56220e17fc0be51789e2f299b64e25303441fb5759b49007f8f9dac" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.bumptech.glide" name="disklrucache" version="4.12.0">
|
||||
<artifact name="disklrucache-4.12.0.jar">
|
||||
<sha256 value="6f0cc9069646ac582ee78dbf621e90303ea200b9ce41c20ac368e925ed456379" origin="Generated by Gradle"/>
|
||||
@@ -3240,6 +3410,16 @@
|
||||
<sha256 value="ec32c33f5b289fd7b0a54485e27392f896b239cefd533385e262de1530190c3f" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.bumptech.glide" name="ktx" version="1.0.0-alpha.1">
|
||||
<artifact name="ktx-1.0.0-alpha.1.aar">
|
||||
<sha256 value="4748150712e03253bdc5cdf2e0ee061ab7063f89ec8bcef126514da7b0602198" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.bumptech.glide" name="recyclerview-integration" version="4.14.2">
|
||||
<artifact name="recyclerview-integration-4.14.2.aar">
|
||||
<sha256 value="eaad945bb20c6b89114aa20c5c7be40f04072c4eb3970c309752ded9e1195f7f" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.gundy" name="semver4j" version="0.16.4">
|
||||
<artifact name="semver4j-0.16.4-nodeps.jar">
|
||||
<pgp value="55e770230e69cc6de143fb5b62c82e50836eb3ee"/>
|
||||
@@ -3294,6 +3474,21 @@
|
||||
<sha256 value="cd6db17a11a31ede794ccbd1df0e4d9750f640234731f21cff885a9997277e81" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.accompanist" name="accompanist-drawablepainter" version="0.25.1">
|
||||
<artifact name="accompanist-drawablepainter-0.25.1.aar">
|
||||
<sha256 value="57ed676b60b0f7d72b051613dc3d7ceb0295a90bcdca7c9316ff33dbff8ab33a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.accompanist" name="accompanist-themeadapter-core" version="0.30.1">
|
||||
<artifact name="accompanist-themeadapter-core-0.30.1.aar">
|
||||
<sha256 value="8df37ee7b51516e4b2640bb02e87326e89b5d0fcd5d566fdd040697aa5a17302" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.accompanist" name="accompanist-themeadapter-material" version="0.30.1">
|
||||
<artifact name="accompanist-themeadapter-material-0.30.1.aar">
|
||||
<sha256 value="4b36a29bc2cbc50dcd41421fc50a61d60df61533cbdd2225c965e6a2ea3f9ab9" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.android" name="annotations" version="4.1.1.4">
|
||||
<artifact name="annotations-4.1.1.4.jar">
|
||||
<pgp value="0f07d1201bddab67cfb84eb479752db6c966f0b8"/>
|
||||
@@ -3991,6 +4186,11 @@
|
||||
<sha256 value="b29c1c21e52ed6238cd3fed39d880a17ecf2360118604548cea8821be6801e1c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.journeyapps" name="zxing-android-embedded" version="4.3.0">
|
||||
<artifact name="zxing-android-embedded-4.3.0.aar">
|
||||
<sha256 value="4ab03353127c34e55cbb80fbc9a34031decbcfb1ec5e8f991944d2d494621a33" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.linkedin.dexmaker" name="dexmaker" version="2.28.1">
|
||||
<artifact name="dexmaker-2.28.1.jar">
|
||||
<pgp value="8df3b0aa23ed78be5233f6c2dea3d207428ef16d"/>
|
||||
@@ -8499,6 +8699,11 @@
|
||||
<sha256 value="8f3fffcfde2b725da91ebf21d8282eea5a29e04659454edd1054b34419f04031" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="1.5.30">
|
||||
<artifact name="kotlin-stdlib-common-1.5.30.jar">
|
||||
<sha256 value="8eb3ac530a978422e0f8d0bba78ba2c628bec997dc2f1aa4ef8c5b854e3764b8" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="1.5.31">
|
||||
<artifact name="kotlin-stdlib-common-1.5.31.jar">
|
||||
<sha256 value="dfa2a18e26b028388ee1968d199bf6f166f737ab7049c25a5e2da614404e22ad" origin="Generated by Gradle"/>
|
||||
@@ -8989,6 +9194,11 @@
|
||||
<sha256 value="51bc74326401b4d3fa4e784f89c51c7932ee52998b619271e88f175dead82242" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="atomicfu" version="0.16.1">
|
||||
<artifact name="atomicfu-metadata-0.16.1-all.jar">
|
||||
<sha256 value="9e3c37269f9d4ffc3edbd4f667e42fe27e92b06bb98e6815da6f19e635275654" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="atomicfu" version="0.16.3">
|
||||
<artifact name="atomicfu-metadata-0.16.3-all.jar">
|
||||
<sha256 value="c3c0546dd33e0ef75782734d9703eb3583a28414b1d4464fcbde56d70a7d5a6d" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
@@ -9058,6 +9268,11 @@
|
||||
<sha256 value="f36ea75c31934bfad0682cfc435cce922e28b3bffa5af26cf86f07db13008f8a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.5.0">
|
||||
<artifact name="kotlinx-coroutines-android-1.5.0.jar">
|
||||
<sha256 value="7099198391d673c199fea084423d9f3fdc79470acba19111330c7f88504279c7" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.5.2">
|
||||
<artifact name="kotlinx-coroutines-android-1.5.2.jar">
|
||||
<sha256 value="86cf9892b0bd5306a8f4d7ad8a82356f614dc7d519eb3063b0887d7c2b405928" origin="Generated by Gradle"/>
|
||||
@@ -9098,6 +9313,11 @@
|
||||
<sha256 value="f8c8b7485d4a575e38e5e94945539d1d4eccd3228a199e1a9aa094e8c26174ee" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.5.0">
|
||||
<artifact name="kotlinx-coroutines-core-metadata-1.5.0-all.jar">
|
||||
<sha256 value="fd58f72f025aa044b09b8b18299012f0d5710632834bcfab3aee32d3b1f26a88" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.5.2">
|
||||
<artifact name="kotlinx-coroutines-core-metadata-1.5.2-all.jar">
|
||||
<sha256 value="4d19a1c1c82bd973d034644f4ffa3d5355cb61bd34575aff86cc609e0e41d6e1" origin="Generated by Gradle because artifact wasn't signed"/>
|
||||
|
||||
Reference in New Issue
Block a user